My goal for this week is to continue reorganizing the application folder structure, refining the codebase, and refactoring the code.
If the application folder structure and codebase are reorganized in an orderly manner, the program will become more maintainable and navigable without causing significant disruptions or errors.
I have finished moving all the files into their folders and reduced the codebase by another 5,000 lines. Originally, the codebase had 47,978 lines; now, it has 35,483. The difference is 12,495 lines, about 26% of the original codebase. The final step to complete the organization would be to move all the source code files into the src folder. But this is a big undertaking, as it involves separating the source code from local files and reconfiguring the file paths through GlobalSettings. I plan to tackle this gradually.
I was able to document more instances of unwanted errors while using the app. One of them is the error:
Failed to find a valid link for ID: ####. Please make sure this ID is available in the selected database.
There's a mismatch between the fetched links displayed in the table and their availability for downloading. This is an issue that I will be looking at for my next steps.
Image 1:
Image 2:
Apart from continuing to refactor and reorganize the code, I plan to implement lazy initialization in the application. This means that resources (such as functions and classes) will only be created or initialized when needed. All the windows are initialized at once during startup, which could slow the program during usage. By implementing lazy initialization, the initialization time will be distributed throughout the program's usage, making delays more negligible.
I am also looking to implement a new feature in CASPER. The details of this feature are still being worked on. Once the concept is clear, I will begin experimenting before integrating it into CASPER. This is one of the key topics Dr. Trinh is looking for during our meeting this week.
The following are the remaining items on my agenda for application development:
|
@@ -1,289 +0,0 @@
|
|
| 1 |
-
from PyQt5 import QtWidgets, Qt, QtGui, QtCore, uic
|
| 2 |
-
import GlobalSettings
|
| 3 |
-
import traceback
|
| 4 |
-
import math
|
| 5 |
-
|
| 6 |
-
#global logger
|
| 7 |
-
logger = GlobalSettings.logger
|
| 8 |
-
|
| 9 |
-
######################################################
|
| 10 |
-
# CoTargeting class: This class is a window that lets the user select which endonucleases to co-target with
|
| 11 |
-
# inputs are from the user and from results
|
| 12 |
-
# from results: the organism name and the list of endonucleases for that organism
|
| 13 |
-
# from user: which endonucleases to co-target
|
| 14 |
-
######################################################
|
| 15 |
-
class CoTargeting(QtWidgets.QMainWindow):
|
| 16 |
-
|
| 17 |
-
def __init__(self, path):
|
| 18 |
-
try:
|
| 19 |
-
# pyqt stuff
|
| 20 |
-
super(CoTargeting, self).__init__()
|
| 21 |
-
uic.loadUi(GlobalSettings.appdir + 'cotargeting.ui', self)
|
| 22 |
-
self.setWindowIcon(QtGui.QIcon(GlobalSettings.appdir + "cas9image.ico"))
|
| 23 |
-
self.setWindowTitle("Co-targeting")
|
| 24 |
-
|
| 25 |
-
# endo_table stuff
|
| 26 |
-
self.endo_table.setColumnCount(1) # hardcoded because there will always be 1 columns
|
| 27 |
-
self.endo_table.setShowGrid(True)
|
| 28 |
-
self.endo_table.setHorizontalHeaderLabels("Endonuclease;".split(";"))
|
| 29 |
-
self.endo_table.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
|
| 30 |
-
self.endo_table.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
|
| 31 |
-
self.endo_table.setSelectionMode(QtWidgets.QAbstractItemView.MultiSelection)
|
| 32 |
-
self.endo_table.horizontalHeader().setSectionResizeMode(0, QtWidgets.QHeaderView.Stretch) #Ensures last column goes to the edge of table
|
| 33 |
-
|
| 34 |
-
# variables
|
| 35 |
-
self.info_path = path
|
| 36 |
-
|
| 37 |
-
# button connections
|
| 38 |
-
self.cancel_button.clicked.connect(self.cancel_function)
|
| 39 |
-
self.submit_button.clicked.connect(self.submission_function)
|
| 40 |
-
|
| 41 |
-
#scale UI
|
| 42 |
-
self.scaleUI()
|
| 43 |
-
|
| 44 |
-
except Exception as e:
|
| 45 |
-
logger.critical("Error initializing CoTargeting class.")
|
| 46 |
-
logger.critical(e)
|
| 47 |
-
logger.critical(traceback.format_exc())
|
| 48 |
-
msgBox = QtWidgets.QMessageBox()
|
| 49 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 50 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 51 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 52 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 53 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 54 |
-
msgBox.exec()
|
| 55 |
-
|
| 56 |
-
exit(-1)
|
| 57 |
-
|
| 58 |
-
#scale UI based on current screen
|
| 59 |
-
def scaleUI(self):
|
| 60 |
-
try:
|
| 61 |
-
self.repaint()
|
| 62 |
-
QtWidgets.QApplication.processEvents()
|
| 63 |
-
|
| 64 |
-
screen = self.screen()
|
| 65 |
-
dpi = screen.physicalDotsPerInch()
|
| 66 |
-
width = screen.geometry().width()
|
| 67 |
-
height = screen.geometry().height()
|
| 68 |
-
|
| 69 |
-
# font scaling
|
| 70 |
-
fontSize = 12
|
| 71 |
-
self.fontSize = fontSize
|
| 72 |
-
self.centralWidget().setStyleSheet("font: " + str(fontSize) + "pt 'Arial';")
|
| 73 |
-
|
| 74 |
-
# CASPER header scaling
|
| 75 |
-
fontSize = 20
|
| 76 |
-
self.title.setStyleSheet("font: bold " + str(fontSize) + "pt 'Arial';")
|
| 77 |
-
|
| 78 |
-
self.adjustSize()
|
| 79 |
-
|
| 80 |
-
currentWidth = self.size().width()
|
| 81 |
-
currentHeight = self.size().height()
|
| 82 |
-
|
| 83 |
-
# window scaling
|
| 84 |
-
# 1920x1080 => 850x750
|
| 85 |
-
scaledWidth = int((width * 450) / 1920)
|
| 86 |
-
scaledHeight = int((height * 375) / 1080)
|
| 87 |
-
|
| 88 |
-
if scaledHeight < currentHeight:
|
| 89 |
-
scaledHeight = currentHeight
|
| 90 |
-
if scaledWidth < currentWidth:
|
| 91 |
-
scaledWidth = currentWidth
|
| 92 |
-
|
| 93 |
-
screen = QtWidgets.QApplication.desktop().screenNumber(QtWidgets.QApplication.desktop().cursor().pos())
|
| 94 |
-
centerPoint = QtWidgets.QApplication.desktop().screenGeometry(screen).center()
|
| 95 |
-
x = centerPoint.x()
|
| 96 |
-
y = centerPoint.y()
|
| 97 |
-
x = x - (math.ceil(scaledWidth / 2))
|
| 98 |
-
y = y - (math.ceil(scaledHeight / 2))
|
| 99 |
-
self.setGeometry(x, y, scaledWidth, scaledHeight)
|
| 100 |
-
|
| 101 |
-
self.repaint()
|
| 102 |
-
QtWidgets.QApplication.processEvents()
|
| 103 |
-
except Exception as e:
|
| 104 |
-
logger.critical("Error in scaleUI() in cotargeting in results.")
|
| 105 |
-
logger.critical(e)
|
| 106 |
-
logger.critical(traceback.format_exc())
|
| 107 |
-
msgBox = QtWidgets.QMessageBox()
|
| 108 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 109 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 110 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 111 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 112 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 113 |
-
msgBox.exec()
|
| 114 |
-
|
| 115 |
-
exit(-1)
|
| 116 |
-
|
| 117 |
-
#center UI on current screen
|
| 118 |
-
def centerUI(self):
|
| 119 |
-
try:
|
| 120 |
-
self.repaint()
|
| 121 |
-
QtWidgets.QApplication.processEvents()
|
| 122 |
-
|
| 123 |
-
# center window on current screen
|
| 124 |
-
width = self.width()
|
| 125 |
-
height = self.height()
|
| 126 |
-
screen = QtWidgets.QApplication.desktop().screenNumber(QtWidgets.QApplication.desktop().cursor().pos())
|
| 127 |
-
centerPoint = QtWidgets.QApplication.desktop().screenGeometry(screen).center()
|
| 128 |
-
x = centerPoint.x()
|
| 129 |
-
y = centerPoint.y()
|
| 130 |
-
x = x - (math.ceil(width / 2))
|
| 131 |
-
y = y - (math.ceil(height / 2))
|
| 132 |
-
self.setGeometry(x, y, width, height)
|
| 133 |
-
|
| 134 |
-
self.repaint()
|
| 135 |
-
QtWidgets.QApplication.processEvents()
|
| 136 |
-
except Exception as e:
|
| 137 |
-
logger.critical("Error in centerUI() in cotargeting in results.")
|
| 138 |
-
logger.critical(e)
|
| 139 |
-
logger.critical(traceback.format_exc())
|
| 140 |
-
msgBox = QtWidgets.QMessageBox()
|
| 141 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 142 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 143 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 144 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 145 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 146 |
-
msgBox.exec()
|
| 147 |
-
|
| 148 |
-
exit(-1)
|
| 149 |
-
|
| 150 |
-
# launches the window
|
| 151 |
-
# it is expecting endo_choices in the form of a list, and the orgName in the form of a string
|
| 152 |
-
# it sets the organism name, and sets the table as well
|
| 153 |
-
def launch(self, endo_choices, orgName):
|
| 154 |
-
try:
|
| 155 |
-
self.orgName.setText(orgName)
|
| 156 |
-
setTableList = list()
|
| 157 |
-
# only get the endo choices that were original
|
| 158 |
-
for item in endo_choices:
|
| 159 |
-
checkList = item.split(",")
|
| 160 |
-
if len(checkList) == 1 and "|" not in item: #Prevent cotarget endos from being added back in
|
| 161 |
-
setTableList.append(item)
|
| 162 |
-
|
| 163 |
-
# go through and set each table item, but also set the row count
|
| 164 |
-
self.endo_table.setRowCount(len(setTableList))
|
| 165 |
-
loopCount = 0
|
| 166 |
-
for item in setTableList:
|
| 167 |
-
tabWidget = QtWidgets.QTableWidgetItem(item)
|
| 168 |
-
self.endo_table.setItem(loopCount, 0, tabWidget)
|
| 169 |
-
loopCount += 1
|
| 170 |
-
self.endo_table.resizeColumnsToContents()
|
| 171 |
-
|
| 172 |
-
# now show
|
| 173 |
-
self.centerUI()
|
| 174 |
-
self.show()
|
| 175 |
-
self.activateWindow()
|
| 176 |
-
except Exception as e:
|
| 177 |
-
logger.critical("Error in launch() in CoTargeting.")
|
| 178 |
-
logger.critical(e)
|
| 179 |
-
logger.critical(traceback.format_exc())
|
| 180 |
-
msgBox = QtWidgets.QMessageBox()
|
| 181 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 182 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 183 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 184 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 185 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 186 |
-
msgBox.exec()
|
| 187 |
-
|
| 188 |
-
exit(-1)
|
| 189 |
-
|
| 190 |
-
# this is the cancel function
|
| 191 |
-
# it clears the table, sets the organism to nothing, and hides the window
|
| 192 |
-
def cancel_function(self):
|
| 193 |
-
try:
|
| 194 |
-
self.endo_table.clearContents()
|
| 195 |
-
self.endo_table.setRowCount(0)
|
| 196 |
-
self.orgName.setText("")
|
| 197 |
-
self.hide()
|
| 198 |
-
except Exception as e:
|
| 199 |
-
logger.critical("Error in cancel_function() in CoTargeting.")
|
| 200 |
-
logger.critical(e)
|
| 201 |
-
logger.critical(traceback.format_exc())
|
| 202 |
-
msgBox = QtWidgets.QMessageBox()
|
| 203 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 204 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 205 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 206 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 207 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 208 |
-
msgBox.exec()
|
| 209 |
-
|
| 210 |
-
exit(-1)
|
| 211 |
-
|
| 212 |
-
# this is the submission function.
|
| 213 |
-
# it makes sure the user selects at least 2 endonucleases
|
| 214 |
-
# then it goes through and returns the endonucleases selected
|
| 215 |
-
# once it gets those, it then calls a function in Results that repopulates the table correctly
|
| 216 |
-
def submission_function(self):
|
| 217 |
-
try:
|
| 218 |
-
#get endo data from CASPERinfo
|
| 219 |
-
self.Endos = {}
|
| 220 |
-
f = open(GlobalSettings.appdir + 'CASPERinfo')
|
| 221 |
-
while True:
|
| 222 |
-
line = f.readline()
|
| 223 |
-
if line.startswith('ENDONUCLEASES'):
|
| 224 |
-
while True:
|
| 225 |
-
line = f.readline()
|
| 226 |
-
if (line[0] == "-"):
|
| 227 |
-
break
|
| 228 |
-
line_tokened = line.split(";")
|
| 229 |
-
endo = line_tokened[0]
|
| 230 |
-
self.Endos[endo] = ([line_tokened[2], line_tokened[3], line_tokened[4]],line_tokened[5])
|
| 231 |
-
break
|
| 232 |
-
f.close()
|
| 233 |
-
|
| 234 |
-
# set the selected_list, and make sure they select at least 2 endonucleases
|
| 235 |
-
selected_list = self.endo_table.selectedItems()
|
| 236 |
-
if len(selected_list) <= 1:
|
| 237 |
-
msgBox = QtWidgets.QMessageBox()
|
| 238 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 239 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 240 |
-
msgBox.setWindowTitle("Nothing Selected")
|
| 241 |
-
msgBox.setText(
|
| 242 |
-
"No endonucleases selected. Please select at least 2 endonucleases")
|
| 243 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Ok)
|
| 244 |
-
msgBox.exec()
|
| 245 |
-
|
| 246 |
-
return
|
| 247 |
-
|
| 248 |
-
# go through and get which endonuclease's have been selected
|
| 249 |
-
ret_endo_list = list()
|
| 250 |
-
for i in range(self.endo_table.rowCount()):
|
| 251 |
-
if self.endo_table.item(i, 0).isSelected():
|
| 252 |
-
ret_endo_list.append(self.endo_table.item(i, 0).text())
|
| 253 |
-
|
| 254 |
-
#invalid_flag = False
|
| 255 |
-
for endo1 in ret_endo_list:
|
| 256 |
-
for endo2 in ret_endo_list:
|
| 257 |
-
if endo1 == endo2:
|
| 258 |
-
continue
|
| 259 |
-
endo1_len = sum([int(x) for x in self.Endos[endo1][0]])
|
| 260 |
-
endo2_len = sum([int(x) for x in self.Endos[endo2][0]])
|
| 261 |
-
if endo1_len != endo2_len or self.Endos[endo1][1] != self.Endos[endo2][1]: # If endonucleases don't have the same length gRNA or don't have the same directionality, throw an error
|
| 262 |
-
msgBox = QtWidgets.QMessageBox()
|
| 263 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 264 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 265 |
-
msgBox.setWindowTitle("Invalid Endonucleases")
|
| 266 |
-
msgBox.setText(
|
| 267 |
-
"The selected endonucleases are not compatible.")
|
| 268 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Ok)
|
| 269 |
-
msgBox.exec()
|
| 270 |
-
|
| 271 |
-
return
|
| 272 |
-
|
| 273 |
-
GlobalSettings.mainWindow.Results.co_target_endo_list = ret_endo_list
|
| 274 |
-
GlobalSettings.mainWindow.Results.populate_cotarget_table()
|
| 275 |
-
self.cancel_function()
|
| 276 |
-
except Exception as e:
|
| 277 |
-
logger.critical("Error in submission_function() in CoTargeting.")
|
| 278 |
-
logger.critical(e)
|
| 279 |
-
logger.critical(traceback.format_exc())
|
| 280 |
-
msgBox = QtWidgets.QMessageBox()
|
| 281 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 282 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 283 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 284 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 285 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 286 |
-
msgBox.exec()
|
| 287 |
-
|
| 288 |
-
exit(-1)
|
| 289 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@@ -1,406 +0,0 @@
|
|
| 1 |
-
import sys, os
|
| 2 |
-
from PyQt5 import QtWidgets, uic, QtGui, QtCore, Qt
|
| 3 |
-
import GlobalSettings
|
| 4 |
-
from PyQt5.QtGui import QIntValidator
|
| 5 |
-
import traceback
|
| 6 |
-
import math
|
| 7 |
-
|
| 8 |
-
#global logger
|
| 9 |
-
logger = GlobalSettings.logger
|
| 10 |
-
|
| 11 |
-
class NewEndonuclease(QtWidgets.QMainWindow):
|
| 12 |
-
|
| 13 |
-
def __init__(self):
|
| 14 |
-
try:
|
| 15 |
-
super(NewEndonuclease, self).__init__()
|
| 16 |
-
uic.loadUi(GlobalSettings.appdir + 'newendonuclease.ui', self)
|
| 17 |
-
self.setWindowIcon(Qt.QIcon(GlobalSettings.appdir + "cas9image.ico"))
|
| 18 |
-
self.setWindowTitle('New Endonuclease')
|
| 19 |
-
self.error = False
|
| 20 |
-
pamFlag = False
|
| 21 |
-
|
| 22 |
-
self.onList = []
|
| 23 |
-
self.offList = []
|
| 24 |
-
|
| 25 |
-
self.onList, self.offList = self.get_on_off_data() ### Call function to fill on- and off- data name lists
|
| 26 |
-
|
| 27 |
-
for name in self.onList: ### Add on-target names to drop-down
|
| 28 |
-
self.comboBox.addItem(str(name))
|
| 29 |
-
|
| 30 |
-
for name in self.offList: ### Add off-target names to drop-down
|
| 31 |
-
self.comboBox_2.addItem(str(name))
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
self.submit_button.clicked.connect(self.submit)
|
| 35 |
-
self.cancel_button.clicked.connect(self.cancel)
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
### Set up validators for input fields:
|
| 39 |
-
reg_ex1 = QtCore.QRegExp("[^/\\\\_]+") # No slashes or underscores
|
| 40 |
-
reg_ex2 = QtCore.QRegExp("[^/\\\\_\\s]+") # No slashes, underscores, or spaces
|
| 41 |
-
reg_ex3 = QtCore.QRegExp("[acdefghiklmnpqrstvwyACDEFGHIKLMNPQRSTVWY\S]+") # Only approved PAM characters and no spaces
|
| 42 |
-
input_validator1 = QtGui.QRegExpValidator(reg_ex1, self)
|
| 43 |
-
input_validator2 = QtGui.QRegExpValidator(reg_ex2, self)
|
| 44 |
-
input_validator3 = QtGui.QRegExpValidator(reg_ex3, self)
|
| 45 |
-
self.organism_name.setValidator(input_validator1)
|
| 46 |
-
self.abbreviation.setValidator(input_validator2)
|
| 47 |
-
self.pam_sequence.setValidator(input_validator3)
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
self.seed_length.setValidator(QIntValidator(0,30,self.seed_length))
|
| 51 |
-
self.five_length.setValidator(QIntValidator(0,20,self.five_length))
|
| 52 |
-
self.three_length.setValidator(QIntValidator(0,20,self.three_length))
|
| 53 |
-
|
| 54 |
-
groupbox_style = """
|
| 55 |
-
QGroupBox:title{subcontrol-origin: margin;
|
| 56 |
-
left: 10px;
|
| 57 |
-
padding: 0 5px 0 5px;}
|
| 58 |
-
QGroupBox#groupBox{border: 2px solid rgb(111,181,110);
|
| 59 |
-
border-radius: 9px;
|
| 60 |
-
font: bold 14pt 'Arial';
|
| 61 |
-
margin-top: 10px;}"""
|
| 62 |
-
|
| 63 |
-
self.groupBox.setStyleSheet(groupbox_style)
|
| 64 |
-
self.groupBox_2.setStyleSheet(groupbox_style.replace("groupBox","groupBox_2"))
|
| 65 |
-
self.groupBox_3.setStyleSheet(groupbox_style.replace("groupBox","groupBox_3"))
|
| 66 |
-
|
| 67 |
-
#scale UI
|
| 68 |
-
self.scaleUI()
|
| 69 |
-
|
| 70 |
-
except Exception as e:
|
| 71 |
-
logger.critical("Error initializing NewEndonuclease class.")
|
| 72 |
-
logger.critical(e)
|
| 73 |
-
logger.critical(traceback.format_exc())
|
| 74 |
-
msgBox = QtWidgets.QMessageBox()
|
| 75 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 76 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 77 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 78 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 79 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 80 |
-
msgBox.exec()
|
| 81 |
-
|
| 82 |
-
|
| 83 |
-
exit(-1)
|
| 84 |
-
|
| 85 |
-
#scale UI based on current screen
|
| 86 |
-
def scaleUI(self):
|
| 87 |
-
try:
|
| 88 |
-
self.repaint()
|
| 89 |
-
QtWidgets.QApplication.processEvents()
|
| 90 |
-
|
| 91 |
-
screen = self.screen()
|
| 92 |
-
dpi = screen.physicalDotsPerInch()
|
| 93 |
-
width = screen.geometry().width()
|
| 94 |
-
height = screen.geometry().height()
|
| 95 |
-
|
| 96 |
-
# font scaling
|
| 97 |
-
fontSize = 12
|
| 98 |
-
self.fontSize = fontSize
|
| 99 |
-
self.centralWidget().setStyleSheet("font: " + str(fontSize) + "pt 'Arial';")
|
| 100 |
-
|
| 101 |
-
#title scaling
|
| 102 |
-
fontSize = 20
|
| 103 |
-
self.title.setStyleSheet("font: bold " + str(fontSize) + "pt 'Arial';")
|
| 104 |
-
|
| 105 |
-
self.adjustSize()
|
| 106 |
-
|
| 107 |
-
currentWidth = self.size().width()
|
| 108 |
-
currentHeight = self.size().height()
|
| 109 |
-
|
| 110 |
-
# window scaling
|
| 111 |
-
scaledWidth = int((width * 480) / 1920)
|
| 112 |
-
scaledHeight = int((height * 615) / 1080)
|
| 113 |
-
|
| 114 |
-
if scaledHeight < currentHeight:
|
| 115 |
-
scaledHeight = currentHeight
|
| 116 |
-
if scaledWidth < currentWidth:
|
| 117 |
-
scaledWidth = currentWidth
|
| 118 |
-
|
| 119 |
-
screen = QtWidgets.QApplication.desktop().screenNumber(QtWidgets.QApplication.desktop().cursor().pos())
|
| 120 |
-
centerPoint = QtWidgets.QApplication.desktop().screenGeometry(screen).center()
|
| 121 |
-
x = centerPoint.x()
|
| 122 |
-
y = centerPoint.y()
|
| 123 |
-
x = x - (math.ceil(scaledWidth / 2))
|
| 124 |
-
y = y - (math.ceil(scaledHeight / 2))
|
| 125 |
-
self.setGeometry(x, y, scaledWidth, scaledHeight)
|
| 126 |
-
|
| 127 |
-
self.repaint()
|
| 128 |
-
QtWidgets.QApplication.processEvents()
|
| 129 |
-
|
| 130 |
-
except Exception as e:
|
| 131 |
-
logger.critical("Error in scaleUI() in new endo.")
|
| 132 |
-
logger.critical(e)
|
| 133 |
-
logger.critical(traceback.format_exc())
|
| 134 |
-
msgBox = QtWidgets.QMessageBox()
|
| 135 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 136 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 137 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 138 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 139 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 140 |
-
msgBox.exec()
|
| 141 |
-
|
| 142 |
-
|
| 143 |
-
exit(-1)
|
| 144 |
-
|
| 145 |
-
#center UI on current screen
|
| 146 |
-
def centerUI(self):
|
| 147 |
-
try:
|
| 148 |
-
self.repaint()
|
| 149 |
-
QtWidgets.QApplication.processEvents()
|
| 150 |
-
|
| 151 |
-
#center window on current screen
|
| 152 |
-
width = self.width()
|
| 153 |
-
height = self.height()
|
| 154 |
-
screen = QtWidgets.QApplication.desktop().screenNumber(QtWidgets.QApplication.desktop().cursor().pos())
|
| 155 |
-
centerPoint = QtWidgets.QApplication.desktop().screenGeometry(screen).center()
|
| 156 |
-
x = centerPoint.x()
|
| 157 |
-
y = centerPoint.y()
|
| 158 |
-
x = x - (math.ceil(width / 2))
|
| 159 |
-
y = y - (math.ceil(height / 2))
|
| 160 |
-
self.setGeometry(x, y, width, height)
|
| 161 |
-
|
| 162 |
-
self.repaint()
|
| 163 |
-
QtWidgets.QApplication.processEvents()
|
| 164 |
-
except Exception as e:
|
| 165 |
-
logger.critical("Error in centerUI() in new endo.")
|
| 166 |
-
logger.critical(e)
|
| 167 |
-
logger.critical(traceback.format_exc())
|
| 168 |
-
msgBox = QtWidgets.QMessageBox()
|
| 169 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 170 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 171 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 172 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 173 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 174 |
-
msgBox.exec()
|
| 175 |
-
|
| 176 |
-
|
| 177 |
-
exit(-1)
|
| 178 |
-
|
| 179 |
-
#helper function for writing new endo information to CASPERinfo - used by submit()
|
| 180 |
-
def writeNewEndonuclease(self, newEndonucleaseStr):
|
| 181 |
-
try:
|
| 182 |
-
with open(GlobalSettings.appdir + 'CASPERinfo', 'r') as f, open(GlobalSettings.appdir + "new_file", 'w+') as f1:
|
| 183 |
-
for line in f:
|
| 184 |
-
f1.write(line)
|
| 185 |
-
if 'ENDONUCLEASES' in line:
|
| 186 |
-
f1.write(newEndonucleaseStr + '\n') # Move f1.write(line) above, to write above instead
|
| 187 |
-
os.remove(GlobalSettings.appdir + "CASPERinfo")
|
| 188 |
-
os.rename(GlobalSettings.appdir + "new_file",
|
| 189 |
-
GlobalSettings.appdir + "CASPERinfo") # Rename the new file
|
| 190 |
-
except Exception as e:
|
| 191 |
-
logger.critical("Error in writeNewEndonuclease() in New Endonuclease.")
|
| 192 |
-
logger.critical(e)
|
| 193 |
-
logger.critical(traceback.format_exc())
|
| 194 |
-
msgBox = QtWidgets.QMessageBox()
|
| 195 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 196 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 197 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 198 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 199 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 200 |
-
msgBox.exec()
|
| 201 |
-
|
| 202 |
-
|
| 203 |
-
exit(-1)
|
| 204 |
-
|
| 205 |
-
#submit new endo to CASPERinfo file
|
| 206 |
-
def submit(self):
|
| 207 |
-
try:
|
| 208 |
-
# This is executed when the button is pressed
|
| 209 |
-
name = str(self.organism_name.text())
|
| 210 |
-
abbr = str(self.abbreviation.text())
|
| 211 |
-
crisprtype = str(self.crispr_type.text())
|
| 212 |
-
seed_len = str(self.seed_length.text())
|
| 213 |
-
five_len = str(self.five_length.text())
|
| 214 |
-
three_len = str(self.three_length.text())
|
| 215 |
-
pam = str(self.pam_sequence.text()).upper()
|
| 216 |
-
### Check for multiple PAMs and format if present
|
| 217 |
-
if len(pam.split(','))>0:
|
| 218 |
-
pam = [x.strip() for x in pam.split(',')]
|
| 219 |
-
pam = ",".join(pam)
|
| 220 |
-
### Check for PAM directionality
|
| 221 |
-
if self.five_pam.isChecked():
|
| 222 |
-
pam_dir = str(5)
|
| 223 |
-
else:
|
| 224 |
-
pam_dir = str(3)
|
| 225 |
-
on_scoring = str(self.comboBox.currentText())
|
| 226 |
-
off_scoring = str(self.comboBox_2.currentText())
|
| 227 |
-
length = len(seed_len) + len(five_len) + len(three_len)
|
| 228 |
-
argument_list = [abbr, pam, five_len, seed_len, three_len, pam_dir, name, crisprtype, on_scoring, off_scoring]
|
| 229 |
-
validPAM = ('A', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'V', 'W', 'Y')
|
| 230 |
-
self.error = False;
|
| 231 |
-
|
| 232 |
-
### Error checking for PAM alphabet
|
| 233 |
-
for letter in pam:
|
| 234 |
-
if (letter not in validPAM):
|
| 235 |
-
msgBox = QtWidgets.QMessageBox()
|
| 236 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 237 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 238 |
-
msgBox.setWindowTitle("Invalid PAM")
|
| 239 |
-
msgBox.setText("Invalid characters in PAM Sequence.")
|
| 240 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Ok)
|
| 241 |
-
msgBox.exec()
|
| 242 |
-
return True
|
| 243 |
-
### Error checking for filling out all fields
|
| 244 |
-
for arg in argument_list:
|
| 245 |
-
if ';' in arg:
|
| 246 |
-
msgBox = QtWidgets.QMessageBox()
|
| 247 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 248 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 249 |
-
msgBox.setWindowTitle("Invalid Semicolon")
|
| 250 |
-
msgBox.setText("Invalid character used: ';'")
|
| 251 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Ok)
|
| 252 |
-
msgBox.exec()
|
| 253 |
-
|
| 254 |
-
return True
|
| 255 |
-
elif arg == "":
|
| 256 |
-
msgBox = QtWidgets.QMessageBox()
|
| 257 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 258 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 259 |
-
msgBox.setWindowTitle("Empty Field")
|
| 260 |
-
msgBox.setText("Please fill in all fields.")
|
| 261 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Ok)
|
| 262 |
-
msgBox.exec()
|
| 263 |
-
|
| 264 |
-
return True
|
| 265 |
-
else:
|
| 266 |
-
pass
|
| 267 |
-
|
| 268 |
-
### Check for duplicate endo abbreviations
|
| 269 |
-
for key in GlobalSettings.mainWindow.organisms_to_endos:
|
| 270 |
-
endo = GlobalSettings.mainWindow.organisms_to_endos[key]
|
| 271 |
-
if abbr in endo:
|
| 272 |
-
msgBox = QtWidgets.QMessageBox()
|
| 273 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 274 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 275 |
-
msgBox.setWindowTitle("Duplicate endo name.")
|
| 276 |
-
msgBox.setText("The given abbreviation already exists. Please choose a unique identifier.")
|
| 277 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Ok)
|
| 278 |
-
msgBox.exec()
|
| 279 |
-
|
| 280 |
-
return True
|
| 281 |
-
else:
|
| 282 |
-
pass
|
| 283 |
-
|
| 284 |
-
myString = ""
|
| 285 |
-
for i, arg in enumerate(argument_list):
|
| 286 |
-
if i == len(argument_list)-1: ### Last argument in list
|
| 287 |
-
myString += str(arg)
|
| 288 |
-
else:
|
| 289 |
-
myString += str(arg) + ";"
|
| 290 |
-
|
| 291 |
-
self.writeNewEndonuclease(myString)
|
| 292 |
-
|
| 293 |
-
### Refresh endonuclease dropdown in New Genome
|
| 294 |
-
GlobalSettings.mainWindow.newGenome.fillEndo()
|
| 295 |
-
|
| 296 |
-
self.clear_all()
|
| 297 |
-
self.close()
|
| 298 |
-
except Exception as e:
|
| 299 |
-
logger.critical("Error in submit() in New Endonuclease.")
|
| 300 |
-
logger.critical(e)
|
| 301 |
-
logger.critical(traceback.format_exc())
|
| 302 |
-
msgBox = QtWidgets.QMessageBox()
|
| 303 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 304 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 305 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 306 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 307 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 308 |
-
msgBox.exec()
|
| 309 |
-
|
| 310 |
-
|
| 311 |
-
exit(-1)
|
| 312 |
-
|
| 313 |
-
#cancel and close window
|
| 314 |
-
def cancel(self):
|
| 315 |
-
try:
|
| 316 |
-
self.clear_all()
|
| 317 |
-
self.close()
|
| 318 |
-
except Exception as e:
|
| 319 |
-
logger.critical("Error in cancel() in New Endonuclease.")
|
| 320 |
-
logger.critical(e)
|
| 321 |
-
logger.critical(traceback.format_exc())
|
| 322 |
-
msgBox = QtWidgets.QMessageBox()
|
| 323 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 324 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 325 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 326 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 327 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 328 |
-
msgBox.exec()
|
| 329 |
-
|
| 330 |
-
|
| 331 |
-
exit(-1)
|
| 332 |
-
|
| 333 |
-
# This function clears all of the line edits
|
| 334 |
-
def clear_all(self):
|
| 335 |
-
try:
|
| 336 |
-
self.organism_name.clear()
|
| 337 |
-
self.abbreviation.clear()
|
| 338 |
-
self.crispr_type.clear()
|
| 339 |
-
self.seed_length.clear()
|
| 340 |
-
self.five_length.clear()
|
| 341 |
-
self.three_length.clear()
|
| 342 |
-
self.pam_sequence.clear()
|
| 343 |
-
except Exception as e:
|
| 344 |
-
logger.critical("Error in clear_all() in New Endonuclease.")
|
| 345 |
-
logger.critical(e)
|
| 346 |
-
logger.critical(traceback.format_exc())
|
| 347 |
-
msgBox = QtWidgets.QMessageBox()
|
| 348 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 349 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 350 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 351 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 352 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 353 |
-
msgBox.exec()
|
| 354 |
-
|
| 355 |
-
|
| 356 |
-
exit(-1)
|
| 357 |
-
|
| 358 |
-
# This function parses CASPERinfo to return the names (in lists) of all on-target and off-target scoring data
|
| 359 |
-
def get_on_off_data(self):
|
| 360 |
-
try:
|
| 361 |
-
filename = GlobalSettings.appdir + "CASPERinfo"
|
| 362 |
-
retList_on = []
|
| 363 |
-
retList_off = []
|
| 364 |
-
with open(filename, 'r') as f:
|
| 365 |
-
lines = f.readlines()
|
| 366 |
-
for i, line in enumerate(lines):
|
| 367 |
-
line = str(line)
|
| 368 |
-
if "ON-TARGET DATA" in line:
|
| 369 |
-
index = i
|
| 370 |
-
while "-----" not in line:
|
| 371 |
-
if "DATA:" in line:
|
| 372 |
-
retList_on.append(line.split("DATA:")[-1].strip()) ### Append name of scoring data to on-target name list
|
| 373 |
-
line = lines[index+1]
|
| 374 |
-
index += 1
|
| 375 |
-
else:
|
| 376 |
-
line = lines[index+1]
|
| 377 |
-
index += 1
|
| 378 |
-
continue
|
| 379 |
-
elif "OFF-TARGET MATRICES" in line:
|
| 380 |
-
index = i
|
| 381 |
-
while "-----" not in line:
|
| 382 |
-
if "MATRIX:" in line:
|
| 383 |
-
retList_off.append(line.split("MATRIX:")[-1].strip()) ### Append name of scoring data to off-target name list
|
| 384 |
-
line = lines[index+1]
|
| 385 |
-
index += 1
|
| 386 |
-
else:
|
| 387 |
-
line = lines[index+1]
|
| 388 |
-
index += 1
|
| 389 |
-
continue
|
| 390 |
-
else:
|
| 391 |
-
continue
|
| 392 |
-
return retList_on, retList_off
|
| 393 |
-
except Exception as e:
|
| 394 |
-
logger.critical("Error in get_on_off_data() in New Endonuclease.")
|
| 395 |
-
logger.critical(e)
|
| 396 |
-
logger.critical(traceback.format_exc())
|
| 397 |
-
msgBox = QtWidgets.QMessageBox()
|
| 398 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 399 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 400 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 401 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 402 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 403 |
-
msgBox.exec()
|
| 404 |
-
|
| 405 |
-
|
| 406 |
-
exit(-1)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@@ -1,197 +0,0 @@
|
|
| 1 |
-
import GlobalSettings
|
| 2 |
-
import os
|
| 3 |
-
from PyQt5 import QtWidgets, Qt, uic
|
| 4 |
-
import traceback
|
| 5 |
-
import math
|
| 6 |
-
|
| 7 |
-
#global logger
|
| 8 |
-
logger = GlobalSettings.logger
|
| 9 |
-
|
| 10 |
-
###########################################################
|
| 11 |
-
# closingWindow: this class is a little window where the user can select which files they want to delete
|
| 12 |
-
# Once they hit 'submit' it will delete all of the files selected, and close the program.
|
| 13 |
-
# If no files are selected, the program closes and no files are deleted
|
| 14 |
-
# Inputs are taking from the user (selecting files to delete and hitting submit), as well as GlobalSettings for the files in CSPR_DB
|
| 15 |
-
# Outputs are the files are deleting, and the program is closed
|
| 16 |
-
###########################################################
|
| 17 |
-
class closingWindow(QtWidgets.QMainWindow):
|
| 18 |
-
def __init__(self):
|
| 19 |
-
try:
|
| 20 |
-
# qt stuff
|
| 21 |
-
super(closingWindow, self).__init__()
|
| 22 |
-
uic.loadUi(GlobalSettings.appdir + "closing_window.ui", self)
|
| 23 |
-
self.setWindowTitle("Delete Files")
|
| 24 |
-
self.setWindowIcon(Qt.QIcon(GlobalSettings.appdir + "cas9image.ico"))
|
| 25 |
-
|
| 26 |
-
# button connections
|
| 27 |
-
self.submit_button.clicked.connect(self.submit_and_close)
|
| 28 |
-
|
| 29 |
-
# table stuff
|
| 30 |
-
self.files_table.setColumnCount(1)
|
| 31 |
-
self.files_table.setShowGrid(True)
|
| 32 |
-
self.files_table.setHorizontalHeaderLabels("File Name;".split(";"))
|
| 33 |
-
self.files_table.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
|
| 34 |
-
self.files_table.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
|
| 35 |
-
self.files_table.setSelectionMode(QtWidgets.QAbstractItemView.MultiSelection)
|
| 36 |
-
|
| 37 |
-
#scale UI
|
| 38 |
-
self.scaleUI()
|
| 39 |
-
|
| 40 |
-
except Exception as e:
|
| 41 |
-
logger.critical("Error initializing closingWindow class.")
|
| 42 |
-
logger.critical(e)
|
| 43 |
-
logger.critical(traceback.format_exc())
|
| 44 |
-
msgBox = QtWidgets.QMessageBox()
|
| 45 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 46 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 47 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 48 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 49 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 50 |
-
msgBox.exec()
|
| 51 |
-
|
| 52 |
-
exit(-1)
|
| 53 |
-
|
| 54 |
-
#scale UI based on current screen
|
| 55 |
-
def scaleUI(self):
|
| 56 |
-
try:
|
| 57 |
-
self.repaint()
|
| 58 |
-
QtWidgets.QApplication.processEvents()
|
| 59 |
-
|
| 60 |
-
screen = self.screen()
|
| 61 |
-
dpi = screen.physicalDotsPerInch()
|
| 62 |
-
width = screen.geometry().width()
|
| 63 |
-
height = screen.geometry().height()
|
| 64 |
-
|
| 65 |
-
# font scaling
|
| 66 |
-
fontSize = 12
|
| 67 |
-
self.fontSize = fontSize
|
| 68 |
-
self.centralWidget().setStyleSheet("font: " + str(fontSize) + "pt 'Arial';")
|
| 69 |
-
|
| 70 |
-
self.adjustSize()
|
| 71 |
-
|
| 72 |
-
currentWidth = self.size().width()
|
| 73 |
-
currentHeight = self.size().height()
|
| 74 |
-
|
| 75 |
-
# window scaling
|
| 76 |
-
# 1920x1080 => 1150x650
|
| 77 |
-
scaledWidth = int((width * 400) / 1920)
|
| 78 |
-
scaledHeight = int((height * 300) / 1080)
|
| 79 |
-
|
| 80 |
-
if scaledHeight < currentHeight:
|
| 81 |
-
scaledHeight = currentHeight
|
| 82 |
-
if scaledWidth < currentWidth:
|
| 83 |
-
scaledWidth = currentWidth
|
| 84 |
-
|
| 85 |
-
screen = QtWidgets.QApplication.desktop().screenNumber(QtWidgets.QApplication.desktop().cursor().pos())
|
| 86 |
-
centerPoint = QtWidgets.QApplication.desktop().screenGeometry(screen).center()
|
| 87 |
-
x = centerPoint.x()
|
| 88 |
-
y = centerPoint.y()
|
| 89 |
-
x = x - (math.ceil(scaledWidth / 2))
|
| 90 |
-
y = y - (math.ceil(scaledHeight / 2))
|
| 91 |
-
self.setGeometry(x, y, scaledWidth, scaledHeight)
|
| 92 |
-
|
| 93 |
-
self.repaint()
|
| 94 |
-
QtWidgets.QApplication.processEvents()
|
| 95 |
-
|
| 96 |
-
except Exception as e:
|
| 97 |
-
logger.critical("Error in scaleUI() in closing window.")
|
| 98 |
-
logger.critical(e)
|
| 99 |
-
logger.critical(traceback.format_exc())
|
| 100 |
-
msgBox = QtWidgets.QMessageBox()
|
| 101 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 102 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 103 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 104 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 105 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 106 |
-
msgBox.exec()
|
| 107 |
-
|
| 108 |
-
exit(-1)
|
| 109 |
-
|
| 110 |
-
#center UI on current screen
|
| 111 |
-
def centerUI(self):
|
| 112 |
-
try:
|
| 113 |
-
self.repaint()
|
| 114 |
-
QtWidgets.QApplication.processEvents()
|
| 115 |
-
|
| 116 |
-
#center window on current screen
|
| 117 |
-
width = self.width()
|
| 118 |
-
height = self.height()
|
| 119 |
-
screen = QtWidgets.QApplication.desktop().screenNumber(QtWidgets.QApplication.desktop().cursor().pos())
|
| 120 |
-
centerPoint = QtWidgets.QApplication.desktop().screenGeometry(screen).center()
|
| 121 |
-
x = centerPoint.x()
|
| 122 |
-
y = centerPoint.y()
|
| 123 |
-
x = x - (math.ceil(width / 2))
|
| 124 |
-
y = y - (math.ceil(height / 2))
|
| 125 |
-
self.setGeometry(x, y, width, height)
|
| 126 |
-
|
| 127 |
-
self.repaint()
|
| 128 |
-
QtWidgets.QApplication.processEvents()
|
| 129 |
-
except Exception as e:
|
| 130 |
-
logger.critical("Error in centerUI() in closing window.")
|
| 131 |
-
logger.critical(e)
|
| 132 |
-
logger.critical(traceback.format_exc())
|
| 133 |
-
msgBox = QtWidgets.QMessageBox()
|
| 134 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 135 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 136 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 137 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 138 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 139 |
-
msgBox.exec()
|
| 140 |
-
|
| 141 |
-
exit(-1)
|
| 142 |
-
|
| 143 |
-
# this function will delete selected files, and then close the program
|
| 144 |
-
def submit_and_close(self):
|
| 145 |
-
try:
|
| 146 |
-
# loop through the whole table
|
| 147 |
-
for i in range(self.files_table.rowCount()):
|
| 148 |
-
tabWidget = self.files_table.item(i, 0)
|
| 149 |
-
|
| 150 |
-
# if that specific tab is selected, delete it. otherwise do nothing
|
| 151 |
-
if tabWidget.isSelected():
|
| 152 |
-
os.remove(tabWidget.text())
|
| 153 |
-
|
| 154 |
-
# close the program now
|
| 155 |
-
self.close()
|
| 156 |
-
except Exception as e:
|
| 157 |
-
logger.critical("Error in sumbit_and_close() in closing window.")
|
| 158 |
-
logger.critical(e)
|
| 159 |
-
logger.critical(traceback.format_exc())
|
| 160 |
-
msgBox = QtWidgets.QMessageBox()
|
| 161 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 162 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 163 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 164 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 165 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 166 |
-
msgBox.exec()
|
| 167 |
-
|
| 168 |
-
exit(-1)
|
| 169 |
-
|
| 170 |
-
# this function gets all of the files from the CSPR_DB and puts them all into the table
|
| 171 |
-
def get_files(self):
|
| 172 |
-
try:
|
| 173 |
-
loopCount = 0
|
| 174 |
-
# get the file names from CSPR_DB
|
| 175 |
-
files_names = os.listdir(GlobalSettings.CSPR_DB)
|
| 176 |
-
files_names.sort(key=str.lower)
|
| 177 |
-
self.files_table.setRowCount(len(files_names))
|
| 178 |
-
|
| 179 |
-
# loop through and add them to the table
|
| 180 |
-
for file in files_names:
|
| 181 |
-
tabWidget = QtWidgets.QTableWidgetItem(file)
|
| 182 |
-
self.files_table.setItem(loopCount, 0, tabWidget)
|
| 183 |
-
loopCount += 1
|
| 184 |
-
self.files_table.resizeColumnsToContents()
|
| 185 |
-
except Exception as e:
|
| 186 |
-
logger.critical("Error in get_files() in closing window.")
|
| 187 |
-
logger.critical(e)
|
| 188 |
-
logger.critical(traceback.format_exc())
|
| 189 |
-
msgBox = QtWidgets.QMessageBox()
|
| 190 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 191 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 192 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 193 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 194 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 195 |
-
msgBox.exec()
|
| 196 |
-
|
| 197 |
-
exit(-1)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@@ -1,10 +0,0 @@
|
|
| 1 |
-
from PyQt5 import QtWidgets
|
| 2 |
-
|
| 3 |
-
def show_message(fontSize, icon, title, message, button=QtWidgets.QMessageBox.StandardButton.Close):
|
| 4 |
-
msgBox = QtWidgets.QMessageBox()
|
| 5 |
-
msgBox.setStyleSheet(f"font: {fontSize}pt 'Arial'")
|
| 6 |
-
msgBox.setIcon(icon)
|
| 7 |
-
msgBox.setWindowTitle(title)
|
| 8 |
-
msgBox.setText(message)
|
| 9 |
-
msgBox.addButton(button)
|
| 10 |
-
msgBox.exec()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@@ -0,0 +1,139 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from PyQt5 import QtWidgets, Qt, QtGui, QtCore, uic
|
| 2 |
+
import models.GlobalSettings as GlobalSettings
|
| 3 |
+
import traceback
|
| 4 |
+
import math
|
| 5 |
+
from utils.ui import show_message, show_error, scale_ui, center_ui
|
| 6 |
+
|
| 7 |
+
logger = GlobalSettings.logger
|
| 8 |
+
|
| 9 |
+
######################################################
|
| 10 |
+
# This class is a window that lets the user select which endonucleases to co-target with
|
| 11 |
+
# inputs are from the user and from results
|
| 12 |
+
# from results: the organism name and the list of endonucleases for that organism
|
| 13 |
+
# from user: which endonucleases to co-target
|
| 14 |
+
######################################################
|
| 15 |
+
class CoTargeting(QtWidgets.QMainWindow):
|
| 16 |
+
def __init__(self, path):
|
| 17 |
+
try:
|
| 18 |
+
super(CoTargeting, self).__init__()
|
| 19 |
+
uic.loadUi(GlobalSettings.appdir + 'ui/cotargeting.ui', self)
|
| 20 |
+
self.setWindowIcon(QtGui.QIcon(GlobalSettings.appdir + "cas9image.ico"))
|
| 21 |
+
self.setWindowTitle("Co-targeting")
|
| 22 |
+
|
| 23 |
+
self.endo_table.setColumnCount(1) # hardcoded because there will always be 1 columns
|
| 24 |
+
self.endo_table.setShowGrid(True)
|
| 25 |
+
self.endo_table.setHorizontalHeaderLabels("Endonuclease;".split(";"))
|
| 26 |
+
self.endo_table.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
|
| 27 |
+
self.endo_table.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
|
| 28 |
+
self.endo_table.setSelectionMode(QtWidgets.QAbstractItemView.MultiSelection)
|
| 29 |
+
self.endo_table.horizontalHeader().setSectionResizeMode(0, QtWidgets.QHeaderView.Stretch) #Ensures last column goes to the edge of table
|
| 30 |
+
|
| 31 |
+
self.info_path = path
|
| 32 |
+
|
| 33 |
+
self.cancel_button.clicked.connect(self.cancel_function)
|
| 34 |
+
self.submit_button.clicked.connect(self.submission_function)
|
| 35 |
+
|
| 36 |
+
scale_ui(self, custom_scale_width=450, custom_scale_height=375)
|
| 37 |
+
|
| 38 |
+
except Exception as e:
|
| 39 |
+
show_error("Error initializing CoTargeting class.", e)
|
| 40 |
+
|
| 41 |
+
# launches the window
|
| 42 |
+
# it is expecting endo_choices in the form of a list, and the orgName in the form of a string
|
| 43 |
+
# it sets the organism name, and sets the table as well
|
| 44 |
+
def launch(self, endo_choices, orgName):
|
| 45 |
+
try:
|
| 46 |
+
self.orgName.setText(orgName)
|
| 47 |
+
setTableList = list()
|
| 48 |
+
# only get the endo choices that were original
|
| 49 |
+
for item in endo_choices:
|
| 50 |
+
checkList = item.split(",")
|
| 51 |
+
if len(checkList) == 1 and "|" not in item: #Prevent cotarget endos from being added back in
|
| 52 |
+
setTableList.append(item)
|
| 53 |
+
|
| 54 |
+
# go through and set each table item, but also set the row count
|
| 55 |
+
self.endo_table.setRowCount(len(setTableList))
|
| 56 |
+
loopCount = 0
|
| 57 |
+
for item in setTableList:
|
| 58 |
+
tabWidget = QtWidgets.QTableWidgetItem(item)
|
| 59 |
+
self.endo_table.setItem(loopCount, 0, tabWidget)
|
| 60 |
+
loopCount += 1
|
| 61 |
+
self.endo_table.resizeColumnsToContents()
|
| 62 |
+
|
| 63 |
+
center_ui(self)
|
| 64 |
+
|
| 65 |
+
self.show()
|
| 66 |
+
self.activateWindow()
|
| 67 |
+
except Exception as e:
|
| 68 |
+
show_error("Error in launch() in CoTargeting.", e)
|
| 69 |
+
|
| 70 |
+
# it clears the table, sets the organism to nothing, and hides the window
|
| 71 |
+
def cancel_function(self):
|
| 72 |
+
try:
|
| 73 |
+
self.endo_table.clearContents()
|
| 74 |
+
self.endo_table.setRowCount(0)
|
| 75 |
+
self.orgName.setText("")
|
| 76 |
+
self.hide()
|
| 77 |
+
except Exception as e:
|
| 78 |
+
show_error("Error in cancel_function() in CoTargeting.", e)
|
| 79 |
+
|
| 80 |
+
# this is the submission function.
|
| 81 |
+
# it makes sure the user selects at least 2 endonucleases
|
| 82 |
+
# then it goes through and returns the endonucleases selected
|
| 83 |
+
# once it gets those, it then calls a function in Results that repopulates the table correctly
|
| 84 |
+
def submission_function(self):
|
| 85 |
+
try:
|
| 86 |
+
#get endo data from CASPERinfo
|
| 87 |
+
self.Endos = {}
|
| 88 |
+
f = open(GlobalSettings.appdir + 'CASPERinfo')
|
| 89 |
+
while True:
|
| 90 |
+
line = f.readline()
|
| 91 |
+
if line.startswith('ENDONUCLEASES'):
|
| 92 |
+
while True:
|
| 93 |
+
line = f.readline()
|
| 94 |
+
if (line[0] == "-"):
|
| 95 |
+
break
|
| 96 |
+
line_tokened = line.split(";")
|
| 97 |
+
endo = line_tokened[0]
|
| 98 |
+
self.Endos[endo] = ([line_tokened[2], line_tokened[3], line_tokened[4]],line_tokened[5])
|
| 99 |
+
break
|
| 100 |
+
f.close()
|
| 101 |
+
|
| 102 |
+
# set the selected_list, and make sure they select at least 2 endonucleases
|
| 103 |
+
selected_list = self.endo_table.selectedItems()
|
| 104 |
+
if len(selected_list) <= 1:
|
| 105 |
+
show_message(
|
| 106 |
+
fontSize=12,
|
| 107 |
+
icon=QtWidgets.QMessageBox.Icon.Critical,
|
| 108 |
+
title="Nothing Selected",
|
| 109 |
+
message="No endonucleases selected. Please select at least 2 endonucleases"
|
| 110 |
+
)
|
| 111 |
+
return
|
| 112 |
+
|
| 113 |
+
# go through and get which endonuclease's have been selected
|
| 114 |
+
ret_endo_list = list()
|
| 115 |
+
for i in range(self.endo_table.rowCount()):
|
| 116 |
+
if self.endo_table.item(i, 0).isSelected():
|
| 117 |
+
ret_endo_list.append(self.endo_table.item(i, 0).text())
|
| 118 |
+
|
| 119 |
+
#invalid_flag = False
|
| 120 |
+
for endo1 in ret_endo_list:
|
| 121 |
+
for endo2 in ret_endo_list:
|
| 122 |
+
if endo1 == endo2:
|
| 123 |
+
continue
|
| 124 |
+
endo1_len = sum([int(x) for x in self.Endos[endo1][0]])
|
| 125 |
+
endo2_len = sum([int(x) for x in self.Endos[endo2][0]])
|
| 126 |
+
if endo1_len != endo2_len or self.Endos[endo1][1] != self.Endos[endo2][1]: # If endonucleases don't have the same length gRNA or don't have the same directionality, throw an error
|
| 127 |
+
show_message(
|
| 128 |
+
fontSize=12,
|
| 129 |
+
icon=QtWidgets.QMessageBox.Icon.Critical,
|
| 130 |
+
title="Invalid Endonucleases",
|
| 131 |
+
message="The selected endonucleases are not compatible."
|
| 132 |
+
)
|
| 133 |
+
return
|
| 134 |
+
|
| 135 |
+
GlobalSettings.mainWindow.Results.co_target_endo_list = ret_endo_list
|
| 136 |
+
GlobalSettings.mainWindow.Results.populate_cotarget_table()
|
| 137 |
+
self.cancel_function()
|
| 138 |
+
except Exception as e:
|
| 139 |
+
show_error("Error in submission_function() in CoTargeting.", e)
|
|
@@ -1,22 +1,16 @@
|
|
| 1 |
import os, platform
|
| 2 |
from PyQt5 import QtWidgets, uic, QtCore, QtGui, Qt
|
| 3 |
from functools import partial
|
| 4 |
-
import GlobalSettings
|
| 5 |
-
import
|
| 6 |
-
import traceback
|
| 7 |
-
import math
|
| 8 |
-
from error_handling import show_error
|
| 9 |
-
from common_utils import show_message
|
| 10 |
|
| 11 |
-
#global logger
|
| 12 |
logger = GlobalSettings.logger
|
| 13 |
|
| 14 |
class OffTarget(QtWidgets.QMainWindow):
|
| 15 |
-
|
| 16 |
def __init__(self):
|
| 17 |
try:
|
| 18 |
super(OffTarget, self).__init__()
|
| 19 |
-
uic.loadUi(GlobalSettings.appdir + 'off_target.ui', self)
|
| 20 |
self.setWindowIcon(Qt.QIcon(GlobalSettings.appdir + "cas9image.ico"))
|
| 21 |
self.setWindowTitle("Off-Target Analysis")
|
| 22 |
self.progressBar.setMinimum(0)
|
|
@@ -35,8 +29,6 @@ class OffTarget(QtWidgets.QMainWindow):
|
|
| 35 |
self.bool_temp = False
|
| 36 |
self.running = False
|
| 37 |
self.process = QtCore.QProcess()
|
| 38 |
-
|
| 39 |
-
# make sure to intialize the class variable in init. That way elsewhere and other classes can access it
|
| 40 |
self.output_path = ''
|
| 41 |
|
| 42 |
groupbox_style = """
|
|
@@ -52,117 +44,10 @@ class OffTarget(QtWidgets.QMainWindow):
|
|
| 52 |
self.Step2.setStyleSheet(groupbox_style.replace("Step1", "Step2"))
|
| 53 |
self.Step3.setStyleSheet(groupbox_style.replace("Step1", "Step3"))
|
| 54 |
|
| 55 |
-
|
| 56 |
-
self.scaleUI()
|
| 57 |
-
|
| 58 |
-
except Exception as e:
|
| 59 |
-
logger.critical("Error initializing OffTarget class.")
|
| 60 |
-
logger.critical(e)
|
| 61 |
-
logger.critical(traceback.format_exc())
|
| 62 |
-
msgBox = QtWidgets.QMessageBox()
|
| 63 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 64 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 65 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 66 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 67 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 68 |
-
msgBox.exec()
|
| 69 |
-
|
| 70 |
-
exit(-1)
|
| 71 |
-
|
| 72 |
-
#scale UI based on current screen
|
| 73 |
-
def scaleUI(self):
|
| 74 |
-
try:
|
| 75 |
-
self.repaint()
|
| 76 |
-
QtWidgets.QApplication.processEvents()
|
| 77 |
-
|
| 78 |
-
screen = self.screen()
|
| 79 |
-
dpi = screen.physicalDotsPerInch()
|
| 80 |
-
width = screen.geometry().width()
|
| 81 |
-
height = screen.geometry().height()
|
| 82 |
-
|
| 83 |
-
# font scaling
|
| 84 |
-
fontSize = 12
|
| 85 |
-
self.fontSize = fontSize
|
| 86 |
-
self.centralWidget().setStyleSheet("font: " + str(fontSize) + "pt 'Arial';")
|
| 87 |
-
|
| 88 |
-
# CASPER header scaling
|
| 89 |
-
fontSize = 20
|
| 90 |
-
self.title.setStyleSheet("font: bold " + str(fontSize) + "pt 'Arial';")
|
| 91 |
-
|
| 92 |
-
self.adjustSize()
|
| 93 |
-
|
| 94 |
-
currentWidth = self.size().width()
|
| 95 |
-
currentHeight = self.size().height()
|
| 96 |
|
| 97 |
-
# window scaling
|
| 98 |
-
# 1920x1080 => 850x750
|
| 99 |
-
scaledWidth = int((width * 400) / 1920)
|
| 100 |
-
scaledHeight = int((height * 450) / 1080)
|
| 101 |
-
|
| 102 |
-
if scaledHeight < currentHeight:
|
| 103 |
-
scaledHeight = currentHeight
|
| 104 |
-
if scaledWidth < currentWidth:
|
| 105 |
-
scaledWidth = currentWidth
|
| 106 |
-
|
| 107 |
-
screen = QtWidgets.QApplication.desktop().screenNumber(QtWidgets.QApplication.desktop().cursor().pos())
|
| 108 |
-
centerPoint = QtWidgets.QApplication.desktop().screenGeometry(screen).center()
|
| 109 |
-
x = centerPoint.x()
|
| 110 |
-
y = centerPoint.y()
|
| 111 |
-
x = x - (math.ceil(scaledWidth / 2))
|
| 112 |
-
y = y - (math.ceil(scaledHeight / 2))
|
| 113 |
-
self.setGeometry(x, y, scaledWidth, scaledHeight)
|
| 114 |
-
|
| 115 |
-
self.repaint()
|
| 116 |
-
QtWidgets.QApplication.processEvents()
|
| 117 |
-
|
| 118 |
-
except Exception as e:
|
| 119 |
-
logger.critical("Error in scaleUI() in Off-Target.")
|
| 120 |
-
logger.critical(e)
|
| 121 |
-
logger.critical(traceback.format_exc())
|
| 122 |
-
msgBox = QtWidgets.QMessageBox()
|
| 123 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 124 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 125 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 126 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 127 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 128 |
-
msgBox.exec()
|
| 129 |
-
|
| 130 |
-
|
| 131 |
-
exit(-1)
|
| 132 |
-
|
| 133 |
-
#center UI on current screen
|
| 134 |
-
def centerUI(self):
|
| 135 |
-
try:
|
| 136 |
-
self.repaint()
|
| 137 |
-
QtWidgets.QApplication.processEvents()
|
| 138 |
-
|
| 139 |
-
# center window on current screen
|
| 140 |
-
width = self.width()
|
| 141 |
-
height = self.height()
|
| 142 |
-
screen = QtWidgets.QApplication.desktop().screenNumber(QtWidgets.QApplication.desktop().cursor().pos())
|
| 143 |
-
centerPoint = QtWidgets.QApplication.desktop().screenGeometry(screen).center()
|
| 144 |
-
x = centerPoint.x()
|
| 145 |
-
y = centerPoint.y()
|
| 146 |
-
x = x - (math.ceil(width / 2))
|
| 147 |
-
y = y - (math.ceil(height / 2))
|
| 148 |
-
self.setGeometry(x, y, width, height)
|
| 149 |
-
|
| 150 |
-
self.repaint()
|
| 151 |
-
QtWidgets.QApplication.processEvents()
|
| 152 |
except Exception as e:
|
| 153 |
-
|
| 154 |
-
logger.critical(e)
|
| 155 |
-
logger.critical(traceback.format_exc())
|
| 156 |
-
msgBox = QtWidgets.QMessageBox()
|
| 157 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 158 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 159 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 160 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 161 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 162 |
-
msgBox.exec()
|
| 163 |
-
|
| 164 |
-
|
| 165 |
-
exit(-1)
|
| 166 |
|
| 167 |
#copied from MT to fill in the chromo and endo dropdowns based on CSPR files user provided at the startup
|
| 168 |
def fill_data_dropdown(self):
|
|
@@ -226,19 +111,7 @@ class OffTarget(QtWidgets.QMainWindow):
|
|
| 226 |
self.mismatchcomboBox.addItems(mismatch_list)
|
| 227 |
self.mismatchcomboBox.setCurrentIndex(3) ### Max number of mismatches is 4 by default
|
| 228 |
except Exception as e:
|
| 229 |
-
|
| 230 |
-
logger.critical(e)
|
| 231 |
-
logger.critical(traceback.format_exc())
|
| 232 |
-
msgBox = QtWidgets.QMessageBox()
|
| 233 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 234 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 235 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 236 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 237 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 238 |
-
msgBox.exec()
|
| 239 |
-
|
| 240 |
-
|
| 241 |
-
exit(-1)
|
| 242 |
|
| 243 |
def change_endos(self):
|
| 244 |
try:
|
|
@@ -246,20 +119,8 @@ class OffTarget(QtWidgets.QMainWindow):
|
|
| 246 |
self.cspr_file = self.organisms_to_files[str(self.OrgcomboBox.currentText())][str(self.EndocomboBox.currentText())][0]
|
| 247 |
self.db_file = self.organisms_to_files[str(self.OrgcomboBox.currentText())][str(self.EndocomboBox.currentText())][1]
|
| 248 |
except Exception as e:
|
| 249 |
-
|
| 250 |
-
|
| 251 |
-
logger.critical(traceback.format_exc())
|
| 252 |
-
msgBox = QtWidgets.QMessageBox()
|
| 253 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 254 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 255 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 256 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 257 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 258 |
-
msgBox.exec()
|
| 259 |
-
|
| 260 |
-
|
| 261 |
-
exit(-1)
|
| 262 |
-
|
| 263 |
def update_endos(self):
|
| 264 |
try:
|
| 265 |
#try to disconnect index changed signal on endo dropdown if there is one
|
|
@@ -278,20 +139,8 @@ class OffTarget(QtWidgets.QMainWindow):
|
|
| 278 |
#reconnect index changed signal on endo dropdown
|
| 279 |
self.EndocomboBox.currentIndexChanged.connect(self.change_endos)
|
| 280 |
except Exception as e:
|
| 281 |
-
|
| 282 |
-
|
| 283 |
-
logger.critical(traceback.format_exc())
|
| 284 |
-
msgBox = QtWidgets.QMessageBox()
|
| 285 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 286 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 287 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 288 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 289 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 290 |
-
msgBox.exec()
|
| 291 |
-
|
| 292 |
-
|
| 293 |
-
exit(-1)
|
| 294 |
-
|
| 295 |
#tolerance slider / entry box. Allows for slider to update, or the user to input in text box
|
| 296 |
# def tol_change(self):
|
| 297 |
# try:
|
|
@@ -324,7 +173,7 @@ class OffTarget(QtWidgets.QMainWindow):
|
|
| 324 |
return
|
| 325 |
|
| 326 |
if save_internally:
|
| 327 |
-
full_output_path = os.path.join(GlobalSettings.appdir, 'local_output.txt')
|
| 328 |
else:
|
| 329 |
full_output_path = os.path.join(GlobalSettings.CSPR_DB, output_file_name)
|
| 330 |
if os.path.isfile(full_output_path):
|
|
@@ -341,42 +190,21 @@ class OffTarget(QtWidgets.QMainWindow):
|
|
| 341 |
self.bool_temp = False
|
| 342 |
self.running = False
|
| 343 |
|
| 344 |
-
# #setup arguments for C++ .exe
|
| 345 |
app_path = GlobalSettings.appdir.replace('\\','/')
|
| 346 |
exe_path = os.path.join(app_path, 'OffTargetFolder', 'OT_Win.exe' if platform.system() == 'Windows' else 'OT_Lin' if platform.system() == 'Linux' else 'OT_Mac')
|
| 347 |
-
|
| 348 |
-
|
| 349 |
-
|
| 350 |
-
|
|
|
|
| 351 |
num_of_mismatches = int(self.mismatchcomboBox.currentText())
|
| 352 |
-
|
| 353 |
-
# hsu = GlobalSettings.mainWindow.Results.endo_data[self.EndocomboBox.currentText()][2]
|
| 354 |
-
|
| 355 |
-
# cmd = f'"{exe_path}" "{data_path}" "{endo}" "{cspr_path}" "{db_path}" "{full_output_path}" "{CASPER_info_path}" {num_of_mismatches} {self.tolerance} {"TRUE" if self.AVG.isChecked() else "FALSE"} {"FALSE" if self.AVG.isChecked() else "TRUE"} "{hsu}"'
|
| 356 |
-
|
| 357 |
-
|
| 358 |
-
if (self.AVG.isChecked()):
|
| 359 |
-
avg_output = r'TRUE'
|
| 360 |
-
detailed_output = r' FALSE '
|
| 361 |
-
else:
|
| 362 |
-
avg_output = r'FALSE'
|
| 363 |
-
detailed_output = r' TRUE '
|
| 364 |
|
| 365 |
-
data_path = ' "' + app_path + 'OffTargetFolder/temp.txt' + '"' ##
|
| 366 |
-
cspr_path = ' "' + GlobalSettings.CSPR_DB + '/' + self.cspr_file + '"'
|
| 367 |
-
db_path = ' "' + GlobalSettings.CSPR_DB + '/' + self.db_file + '"'
|
| 368 |
self.output_path = ' "' + full_output_path + '"'
|
| 369 |
-
|
| 370 |
-
|
| 371 |
-
hsu = ' "' + GlobalSettings.mainWindow.Results.endo_data[self.EndocomboBox.currentText()][2] + '"'
|
| 372 |
-
|
| 373 |
-
#create command string
|
| 374 |
-
# cmd = f'"{exe_path}" "{data_path}" "{endo}" "{cspr_path}" "{db_path}" "{full_output_path}" "{CASPER_info_path}" {num_of_mismatches} {self.tolerance} {"TRUE" if self.AVG.isChecked() else "FALSE"} {"FALSE" if self.AVG.isChecked() else "TRUE"} "{hsu}"'
|
| 375 |
-
cmd = f'"{exe_path}"' + data_path + endo + cspr_path + db_path + self.output_path + CASPER_info_path + str(num_of_mismatches) + ' ' + str(self.tolerance) + detailed_output + avg_output + hsu
|
| 376 |
cmd = cmd.replace('/', '\\') if platform.system() == 'Windows' else cmd
|
| 377 |
|
| 378 |
-
|
| 379 |
-
#used to know when the process is done
|
| 380 |
def finished():
|
| 381 |
self.running = False
|
| 382 |
self.run_clicked = True
|
|
@@ -415,20 +243,8 @@ class OffTarget(QtWidgets.QMainWindow):
|
|
| 415 |
self.running = True
|
| 416 |
self.run_command()
|
| 417 |
except Exception as e:
|
| 418 |
-
|
| 419 |
-
|
| 420 |
-
logger.critical(traceback.format_exc())
|
| 421 |
-
msgBox = QtWidgets.QMessageBox()
|
| 422 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 423 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 424 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 425 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 426 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 427 |
-
msgBox.exec()
|
| 428 |
-
|
| 429 |
-
|
| 430 |
-
exit(-1)
|
| 431 |
-
|
| 432 |
#exit linked to user clicking cancel, resets bools, and kills process if one was running
|
| 433 |
def exit(self):
|
| 434 |
try:
|
|
@@ -438,7 +254,7 @@ class OffTarget(QtWidgets.QMainWindow):
|
|
| 438 |
self.process.kill()
|
| 439 |
self.hide()
|
| 440 |
|
| 441 |
-
local_output_path = os.path.join(GlobalSettings.appdir, 'local_output.txt')
|
| 442 |
|
| 443 |
if os.path.exists(local_output_path):
|
| 444 |
os.remove(local_output_path)
|
|
@@ -446,20 +262,8 @@ class OffTarget(QtWidgets.QMainWindow):
|
|
| 446 |
else:
|
| 447 |
print("Local output file does not exist.")
|
| 448 |
except Exception as e:
|
| 449 |
-
|
| 450 |
-
|
| 451 |
-
logger.critical(traceback.format_exc())
|
| 452 |
-
msgBox = QtWidgets.QMessageBox()
|
| 453 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 454 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 455 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 456 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 457 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 458 |
-
msgBox.exec()
|
| 459 |
-
|
| 460 |
-
|
| 461 |
-
exit(-1)
|
| 462 |
-
|
| 463 |
#closeEvent linked to user pressing the x in the top right of windows, resets bools, and
|
| 464 |
#kills process if there was one running
|
| 465 |
def closeEvent(self, event):
|
|
@@ -470,17 +274,4 @@ class OffTarget(QtWidgets.QMainWindow):
|
|
| 470 |
self.running = False
|
| 471 |
event.accept()
|
| 472 |
except Exception as e:
|
| 473 |
-
|
| 474 |
-
logger.critical(e)
|
| 475 |
-
logger.critical(traceback.format_exc())
|
| 476 |
-
msgBox = QtWidgets.QMessageBox()
|
| 477 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 478 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 479 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 480 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 481 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 482 |
-
msgBox.exec()
|
| 483 |
-
|
| 484 |
-
|
| 485 |
-
exit(-1)
|
| 486 |
-
|
|
|
|
| 1 |
import os, platform
|
| 2 |
from PyQt5 import QtWidgets, uic, QtCore, QtGui, Qt
|
| 3 |
from functools import partial
|
| 4 |
+
import models.GlobalSettings as GlobalSettings
|
| 5 |
+
from utils.ui import show_message, show_error, scale_ui, center_ui
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6 |
|
|
|
|
| 7 |
logger = GlobalSettings.logger
|
| 8 |
|
| 9 |
class OffTarget(QtWidgets.QMainWindow):
|
|
|
|
| 10 |
def __init__(self):
|
| 11 |
try:
|
| 12 |
super(OffTarget, self).__init__()
|
| 13 |
+
uic.loadUi(GlobalSettings.appdir + 'ui/off_target.ui', self)
|
| 14 |
self.setWindowIcon(Qt.QIcon(GlobalSettings.appdir + "cas9image.ico"))
|
| 15 |
self.setWindowTitle("Off-Target Analysis")
|
| 16 |
self.progressBar.setMinimum(0)
|
|
|
|
| 29 |
self.bool_temp = False
|
| 30 |
self.running = False
|
| 31 |
self.process = QtCore.QProcess()
|
|
|
|
|
|
|
| 32 |
self.output_path = ''
|
| 33 |
|
| 34 |
groupbox_style = """
|
|
|
|
| 44 |
self.Step2.setStyleSheet(groupbox_style.replace("Step1", "Step2"))
|
| 45 |
self.Step3.setStyleSheet(groupbox_style.replace("Step1", "Step3"))
|
| 46 |
|
| 47 |
+
scale_ui(self, custom_scale_width=400, custom_scale_height=450)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 48 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 49 |
except Exception as e:
|
| 50 |
+
show_error("Error initializing OffTarget class.", e)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 51 |
|
| 52 |
#copied from MT to fill in the chromo and endo dropdowns based on CSPR files user provided at the startup
|
| 53 |
def fill_data_dropdown(self):
|
|
|
|
| 111 |
self.mismatchcomboBox.addItems(mismatch_list)
|
| 112 |
self.mismatchcomboBox.setCurrentIndex(3) ### Max number of mismatches is 4 by default
|
| 113 |
except Exception as e:
|
| 114 |
+
show_error("Error in fill_data_dropdown() in OffTarget.", e)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 115 |
|
| 116 |
def change_endos(self):
|
| 117 |
try:
|
|
|
|
| 119 |
self.cspr_file = self.organisms_to_files[str(self.OrgcomboBox.currentText())][str(self.EndocomboBox.currentText())][0]
|
| 120 |
self.db_file = self.organisms_to_files[str(self.OrgcomboBox.currentText())][str(self.EndocomboBox.currentText())][1]
|
| 121 |
except Exception as e:
|
| 122 |
+
show_error("Error in change_endos() in OffTarget.", e)
|
| 123 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 124 |
def update_endos(self):
|
| 125 |
try:
|
| 126 |
#try to disconnect index changed signal on endo dropdown if there is one
|
|
|
|
| 139 |
#reconnect index changed signal on endo dropdown
|
| 140 |
self.EndocomboBox.currentIndexChanged.connect(self.change_endos)
|
| 141 |
except Exception as e:
|
| 142 |
+
show_error("Error in update_endos() in OffTarget.", e)
|
| 143 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 144 |
#tolerance slider / entry box. Allows for slider to update, or the user to input in text box
|
| 145 |
# def tol_change(self):
|
| 146 |
# try:
|
|
|
|
| 173 |
return
|
| 174 |
|
| 175 |
if save_internally:
|
| 176 |
+
full_output_path = os.path.join(GlobalSettings.appdir, 'local/local_output.txt')
|
| 177 |
else:
|
| 178 |
full_output_path = os.path.join(GlobalSettings.CSPR_DB, output_file_name)
|
| 179 |
if os.path.isfile(full_output_path):
|
|
|
|
| 190 |
self.bool_temp = False
|
| 191 |
self.running = False
|
| 192 |
|
|
|
|
| 193 |
app_path = GlobalSettings.appdir.replace('\\','/')
|
| 194 |
exe_path = os.path.join(app_path, 'OffTargetFolder', 'OT_Win.exe' if platform.system() == 'Windows' else 'OT_Lin' if platform.system() == 'Linux' else 'OT_Mac')
|
| 195 |
+
data_path = os.path.join(app_path, 'OffTargetFolder', 'temp.txt')
|
| 196 |
+
endo = self.EndocomboBox.currentText()
|
| 197 |
+
cspr_path = os.path.join(GlobalSettings.CSPR_DB, self.cspr_file)
|
| 198 |
+
db_path = os.path.join(GlobalSettings.CSPR_DB, self.db_file)
|
| 199 |
+
CASPER_info_path = os.path.join(app_path, 'CASPERinfo')
|
| 200 |
num_of_mismatches = int(self.mismatchcomboBox.currentText())
|
| 201 |
+
hsu = GlobalSettings.mainWindow.Results.endo_data[self.EndocomboBox.currentText()][2]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 202 |
|
|
|
|
|
|
|
|
|
|
| 203 |
self.output_path = ' "' + full_output_path + '"'
|
| 204 |
+
|
| 205 |
+
cmd = f'"{exe_path}" "{data_path}" "{endo}" "{cspr_path}" "{db_path}" "{full_output_path}" "{CASPER_info_path}" {num_of_mismatches} {self.tolerance} {"TRUE" if self.AVG.isChecked() else "FALSE"} {"FALSE" if self.AVG.isChecked() else "TRUE"} "{hsu}"'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 206 |
cmd = cmd.replace('/', '\\') if platform.system() == 'Windows' else cmd
|
| 207 |
|
|
|
|
|
|
|
| 208 |
def finished():
|
| 209 |
self.running = False
|
| 210 |
self.run_clicked = True
|
|
|
|
| 243 |
self.running = True
|
| 244 |
self.run_command()
|
| 245 |
except Exception as e:
|
| 246 |
+
show_error("Error in run_analysis() in OffTarget.", e)
|
| 247 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 248 |
#exit linked to user clicking cancel, resets bools, and kills process if one was running
|
| 249 |
def exit(self):
|
| 250 |
try:
|
|
|
|
| 254 |
self.process.kill()
|
| 255 |
self.hide()
|
| 256 |
|
| 257 |
+
local_output_path = os.path.join(GlobalSettings.appdir, 'local/local_output.txt')
|
| 258 |
|
| 259 |
if os.path.exists(local_output_path):
|
| 260 |
os.remove(local_output_path)
|
|
|
|
| 262 |
else:
|
| 263 |
print("Local output file does not exist.")
|
| 264 |
except Exception as e:
|
| 265 |
+
show_error("Error in exit() in OffTarget.", e)
|
| 266 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 267 |
#closeEvent linked to user pressing the x in the top right of windows, resets bools, and
|
| 268 |
#kills process if there was one running
|
| 269 |
def closeEvent(self, event):
|
|
|
|
| 274 |
self.running = False
|
| 275 |
event.accept()
|
| 276 |
except Exception as e:
|
| 277 |
+
show_error("Error in closeEvent() in OffTarget.", e)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@@ -1,14 +1,15 @@
|
|
| 1 |
-
from Algorithms import get_table_headers
|
| 2 |
from PyQt5 import QtWidgets, uic, QtCore, QtGui, Qt
|
| 3 |
from Bio.Seq import Seq
|
| 4 |
from Bio import SeqIO
|
| 5 |
-
from CSPRparser import CSPRparser
|
| 6 |
-
import GlobalSettings
|
| 7 |
-
import OffTarget
|
| 8 |
import platform
|
| 9 |
import traceback
|
| 10 |
import math
|
| 11 |
-
from scoring_window import Scoring_Window
|
|
|
|
| 12 |
|
| 13 |
|
| 14 |
#global logger
|
|
@@ -24,7 +25,7 @@ class Results(QtWidgets.QMainWindow):
|
|
| 24 |
def __init__(self, parent=None):
|
| 25 |
try:
|
| 26 |
super(Results, self).__init__(parent)
|
| 27 |
-
uic.loadUi(GlobalSettings.appdir + 'results.ui', self)
|
| 28 |
self.setWindowIcon(Qt.QIcon(GlobalSettings.appdir + "cas9image.ico"))
|
| 29 |
self.setWindowTitle('Results')
|
| 30 |
self.geneViewer.setReadOnly(True)
|
|
@@ -1271,7 +1272,7 @@ class Results(QtWidgets.QMainWindow):
|
|
| 1271 |
self.first_boot = False
|
| 1272 |
self.off_tar_win = OffTarget.OffTarget()
|
| 1273 |
self.off_tar_win.submitButton.clicked.connect(self.refresh_data)
|
| 1274 |
-
self.off_tar_win
|
| 1275 |
ref_org = str(GlobalSettings.mainWindow.orgChoice.currentText()) ### Set default reference organism to the organism that is being targeted
|
| 1276 |
index = self.off_tar_win.OrgcomboBox.findText(ref_org) ### Find organism in combo box list
|
| 1277 |
self.off_tar_win.OrgcomboBox.setCurrentIndex(index) ### Set combo box to appropriate index
|
|
@@ -1644,7 +1645,7 @@ class Filter_Options(QtWidgets.QMainWindow):
|
|
| 1644 |
def __init__(self, parent=None):
|
| 1645 |
try:
|
| 1646 |
super(Filter_Options, self).__init__(parent)
|
| 1647 |
-
uic.loadUi(GlobalSettings.appdir + 'filter_options.ui', self)
|
| 1648 |
self.setWindowIcon(Qt.QIcon(GlobalSettings.appdir + "cas9image.ico"))
|
| 1649 |
self.setWindowTitle("Filter Options")
|
| 1650 |
self.minScoreLine.setText("0")
|
|
|
|
| 1 |
+
from utils.Algorithms import get_table_headers
|
| 2 |
from PyQt5 import QtWidgets, uic, QtCore, QtGui, Qt
|
| 3 |
from Bio.Seq import Seq
|
| 4 |
from Bio import SeqIO
|
| 5 |
+
from models.CSPRparser import CSPRparser
|
| 6 |
+
import models.GlobalSettings as GlobalSettings
|
| 7 |
+
import controllers.OffTarget as OffTarget
|
| 8 |
import platform
|
| 9 |
import traceback
|
| 10 |
import math
|
| 11 |
+
from controllers.scoring_window import Scoring_Window
|
| 12 |
+
from utils.ui import scale_ui, center_ui
|
| 13 |
|
| 14 |
|
| 15 |
#global logger
|
|
|
|
| 25 |
def __init__(self, parent=None):
|
| 26 |
try:
|
| 27 |
super(Results, self).__init__(parent)
|
| 28 |
+
uic.loadUi(GlobalSettings.appdir + 'ui/results.ui', self)
|
| 29 |
self.setWindowIcon(Qt.QIcon(GlobalSettings.appdir + "cas9image.ico"))
|
| 30 |
self.setWindowTitle('Results')
|
| 31 |
self.geneViewer.setReadOnly(True)
|
|
|
|
| 1272 |
self.first_boot = False
|
| 1273 |
self.off_tar_win = OffTarget.OffTarget()
|
| 1274 |
self.off_tar_win.submitButton.clicked.connect(self.refresh_data)
|
| 1275 |
+
center_ui(self.off_tar_win)
|
| 1276 |
ref_org = str(GlobalSettings.mainWindow.orgChoice.currentText()) ### Set default reference organism to the organism that is being targeted
|
| 1277 |
index = self.off_tar_win.OrgcomboBox.findText(ref_org) ### Find organism in combo box list
|
| 1278 |
self.off_tar_win.OrgcomboBox.setCurrentIndex(index) ### Set combo box to appropriate index
|
|
|
|
| 1645 |
def __init__(self, parent=None):
|
| 1646 |
try:
|
| 1647 |
super(Filter_Options, self).__init__(parent)
|
| 1648 |
+
uic.loadUi(GlobalSettings.appdir + 'ui/filter_options.ui', self)
|
| 1649 |
self.setWindowIcon(Qt.QIcon(GlobalSettings.appdir + "cas9image.ico"))
|
| 1650 |
self.setWindowTitle("Filter Options")
|
| 1651 |
self.minScoreLine.setText("0")
|
|
@@ -1,10 +1,10 @@
|
|
| 1 |
from PyQt5 import QtWidgets, Qt, QtGui, QtCore, uic
|
| 2 |
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg
|
| 3 |
from matplotlib.figure import Figure
|
| 4 |
-
import GlobalSettings
|
| 5 |
import matplotlib
|
| 6 |
-
from Algorithms import SeqTranslate
|
| 7 |
-
from CSPRparser import CSPRparser
|
| 8 |
from matplotlib.ticker import MaxNLocator
|
| 9 |
import os
|
| 10 |
import sqlite3
|
|
@@ -18,8 +18,8 @@ from matplotlib.widgets import Slider
|
|
| 18 |
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
|
| 19 |
from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolbar
|
| 20 |
import matplotlib.pyplot as plt
|
| 21 |
-
|
| 22 |
-
|
| 23 |
logger = GlobalSettings.logger
|
| 24 |
|
| 25 |
class Multitargeting(QtWidgets.QMainWindow):
|
|
@@ -27,7 +27,7 @@ class Multitargeting(QtWidgets.QMainWindow):
|
|
| 27 |
try:
|
| 28 |
self.count = 0
|
| 29 |
super(Multitargeting, self).__init__()
|
| 30 |
-
uic.loadUi(GlobalSettings.appdir + 'mt.ui', self)
|
| 31 |
self.setWindowIcon(Qt.QIcon(GlobalSettings.appdir + "cas9image.ico"))
|
| 32 |
self.multitargeting_statistics = Multitargeting_Statistics()
|
| 33 |
|
|
@@ -85,7 +85,7 @@ class Multitargeting(QtWidgets.QMainWindow):
|
|
| 85 |
self.selectAll.stateChanged.connect(self.select_all)
|
| 86 |
self.selectAll.setEnabled(False)
|
| 87 |
|
| 88 |
-
# go back to main
|
| 89 |
self.back_button.clicked.connect(self.go_back)
|
| 90 |
|
| 91 |
# Statistics storage variables
|
|
@@ -98,14 +98,12 @@ class Multitargeting(QtWidgets.QMainWindow):
|
|
| 98 |
self.bar_coords = []
|
| 99 |
self.seed_id_seq_pair = {}
|
| 100 |
|
| 101 |
-
# parser object
|
| 102 |
self.parser = CSPRparser("")
|
| 103 |
|
| 104 |
self.ready_chromo_min_max = True
|
| 105 |
self.ready_chromo_make_graph = True
|
| 106 |
self.info_path = os.getcwd()
|
| 107 |
|
| 108 |
-
##################################
|
| 109 |
self.scene = QtWidgets.QGraphicsScene()
|
| 110 |
self.scene2 = QtWidgets.QGraphicsScene()
|
| 111 |
self.graphicsView_2.setScene(self.scene2)
|
|
@@ -120,22 +118,14 @@ class Multitargeting(QtWidgets.QMainWindow):
|
|
| 120 |
self.sql_settings = sql_query_settings()
|
| 121 |
self.sql_settings.row_count.textChanged.connect(self.sql_row_count_value_changed)
|
| 122 |
|
| 123 |
-
#scale UI
|
| 124 |
self.first_show = True
|
| 125 |
-
self
|
|
|
|
|
|
|
|
|
|
| 126 |
|
| 127 |
except Exception as e:
|
| 128 |
-
|
| 129 |
-
logger.critical(e)
|
| 130 |
-
logger.critical(traceback.format_exc())
|
| 131 |
-
msgBox = QtWidgets.QMessageBox()
|
| 132 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 133 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 134 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 135 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 136 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 137 |
-
msgBox.exec()
|
| 138 |
-
exit(-1)
|
| 139 |
|
| 140 |
def select_all(self):
|
| 141 |
try:
|
|
@@ -144,164 +134,39 @@ class Multitargeting(QtWidgets.QMainWindow):
|
|
| 144 |
else:
|
| 145 |
self.table.clearSelection()
|
| 146 |
except Exception as e:
|
| 147 |
-
|
| 148 |
-
logger.critical(e)
|
| 149 |
-
logger.critical(traceback.format_exc())
|
| 150 |
-
msgBox = QtWidgets.QMessageBox()
|
| 151 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 152 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 153 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 154 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 155 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 156 |
-
msgBox.exec()
|
| 157 |
-
|
| 158 |
-
|
| 159 |
-
exit(-1)
|
| 160 |
-
|
| 161 |
-
|
| 162 |
-
def scaleUI(self):
|
| 163 |
-
try:
|
| 164 |
-
self.repaint()
|
| 165 |
-
QtWidgets.QApplication.processEvents()
|
| 166 |
-
|
| 167 |
-
screen = self.screen()
|
| 168 |
-
dpi = screen.physicalDotsPerInch()
|
| 169 |
-
self.dpi = dpi
|
| 170 |
-
width = screen.geometry().width()
|
| 171 |
-
height = screen.geometry().height()
|
| 172 |
-
|
| 173 |
-
# font scaling
|
| 174 |
-
fontSize = 12
|
| 175 |
-
self.fontSize = fontSize
|
| 176 |
-
self.centralWidget().setStyleSheet("font: " + str(fontSize) + "pt 'Arial';" )
|
| 177 |
-
self.menuBar().setStyleSheet("font: " + str(fontSize) + "pt 'Arial';" )
|
| 178 |
-
|
| 179 |
-
#CASPER header scaling
|
| 180 |
-
fontSize = 30
|
| 181 |
-
self.title.setStyleSheet("font: bold " + str(fontSize) + "pt 'Arial';")
|
| 182 |
-
|
| 183 |
-
self.adjustSize()
|
| 184 |
-
|
| 185 |
-
currentWidth = self.size().width()
|
| 186 |
-
currentHeight = self.size().height()
|
| 187 |
-
|
| 188 |
-
#make sure chromosome viewer doesnt get too small
|
| 189 |
-
self.groupBox_2.setMinimumHeight(int(0.3 * height))
|
| 190 |
-
|
| 191 |
-
# window scaling
|
| 192 |
-
scaledWidth = int((width * 1400) / 1920)
|
| 193 |
-
scaledHeight = int((height * 900) / 1080)
|
| 194 |
-
|
| 195 |
-
if scaledHeight < currentHeight:
|
| 196 |
-
scaledHeight = currentHeight
|
| 197 |
-
if scaledWidth < currentWidth:
|
| 198 |
-
scaledWidth = currentWidth
|
| 199 |
-
|
| 200 |
-
#set min width of table
|
| 201 |
-
self.table.setMinimumWidth(int(0.5 * scaledWidth))
|
| 202 |
-
|
| 203 |
-
screen = QtWidgets.QApplication.desktop().screenNumber(QtWidgets.QApplication.desktop().cursor().pos())
|
| 204 |
-
centerPoint = QtWidgets.QApplication.desktop().screenGeometry(screen).center()
|
| 205 |
-
x = centerPoint.x()
|
| 206 |
-
y = centerPoint.y()
|
| 207 |
-
x = x - (math.ceil(scaledWidth / 2))
|
| 208 |
-
y = y - (math.ceil(scaledHeight / 2))
|
| 209 |
-
|
| 210 |
-
self.setGeometry(x, y, scaledWidth, scaledHeight)
|
| 211 |
-
self.repaint()
|
| 212 |
-
QtWidgets.QApplication.processEvents()
|
| 213 |
-
|
| 214 |
-
except Exception as e:
|
| 215 |
-
logger.critical("Error in scaleUI() in multi-targeting.")
|
| 216 |
-
logger.critical(e)
|
| 217 |
-
logger.critical(traceback.format_exc())
|
| 218 |
-
msgBox = QtWidgets.QMessageBox()
|
| 219 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 220 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 221 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 222 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 223 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 224 |
-
msgBox.exec()
|
| 225 |
-
|
| 226 |
-
exit(-1)
|
| 227 |
-
|
| 228 |
-
def centerUI(self):
|
| 229 |
-
self.repaint()
|
| 230 |
-
QtWidgets.QApplication.processEvents()
|
| 231 |
-
|
| 232 |
-
width = self.width()
|
| 233 |
-
height = self.height()
|
| 234 |
-
# scale/center window
|
| 235 |
-
screen = QtWidgets.QApplication.desktop().screenNumber(QtWidgets.QApplication.desktop().cursor().pos())
|
| 236 |
-
centerPoint = QtWidgets.QApplication.desktop().screenGeometry(screen).center()
|
| 237 |
-
x = centerPoint.x()
|
| 238 |
-
y = centerPoint.y()
|
| 239 |
-
x = x - (math.ceil(width / 2))
|
| 240 |
-
y = y - (math.ceil(height / 2))
|
| 241 |
-
self.setGeometry(x, y, width, height)
|
| 242 |
-
|
| 243 |
-
self.Analyze_Button.resize(200, 200)
|
| 244 |
-
|
| 245 |
-
self.repaint()
|
| 246 |
-
QtWidgets.QApplication.processEvents()
|
| 247 |
|
| 248 |
def export_tool(self):
|
| 249 |
try:
|
| 250 |
select_items = self.table.selectedItems()
|
| 251 |
if len(select_items) <= 0:
|
| 252 |
-
|
| 253 |
-
|
| 254 |
-
|
| 255 |
-
|
| 256 |
-
|
| 257 |
-
|
| 258 |
-
msgBox.exec()
|
| 259 |
-
|
| 260 |
return
|
| 261 |
GlobalSettings.mainWindow.export_tool_window.launch(select_items,"mt")
|
| 262 |
except Exception as e:
|
| 263 |
-
|
| 264 |
-
logger.critical(e)
|
| 265 |
-
logger.critical(traceback.format_exc())
|
| 266 |
-
msgBox = QtWidgets.QMessageBox()
|
| 267 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 268 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 269 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 270 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 271 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 272 |
-
msgBox.exec()
|
| 273 |
-
|
| 274 |
-
exit(-1)
|
| 275 |
|
| 276 |
def show_statistics(self):
|
| 277 |
try:
|
| 278 |
if (self.line_bool and self.bar_bool):
|
| 279 |
-
self.multitargeting_statistics
|
| 280 |
self.multitargeting_statistics.show()
|
| 281 |
self.multitargeting_statistics.activateWindow()
|
| 282 |
else:
|
| 283 |
-
|
| 284 |
-
|
| 285 |
-
|
| 286 |
-
|
| 287 |
-
|
| 288 |
-
|
| 289 |
-
msgBox.exec()
|
| 290 |
-
|
| 291 |
return True
|
| 292 |
except Exception as e:
|
| 293 |
-
|
| 294 |
-
logger.critical(e)
|
| 295 |
-
logger.critical(traceback.format_exc())
|
| 296 |
-
msgBox = QtWidgets.QMessageBox()
|
| 297 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 298 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 299 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 300 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 301 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 302 |
-
msgBox.exec()
|
| 303 |
-
|
| 304 |
-
exit(-1)
|
| 305 |
|
| 306 |
#event handler to show details of targets in chromosome viewer while hovering over canvases
|
| 307 |
def chromosome_event_handler(self, event):
|
|
@@ -338,64 +203,29 @@ class Multitargeting(QtWidgets.QMainWindow):
|
|
| 338 |
text.setFont(font)
|
| 339 |
|
| 340 |
except Exception as e:
|
| 341 |
-
|
| 342 |
-
logger.critical(e)
|
| 343 |
-
logger.critical(traceback.format_exc())
|
| 344 |
-
msgBox = QtWidgets.QMessageBox()
|
| 345 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 346 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 347 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 348 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 349 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 350 |
-
msgBox.exec()
|
| 351 |
-
|
| 352 |
-
exit(-1)
|
| 353 |
|
| 354 |
def launch(self):
|
| 355 |
try:
|
| 356 |
self.get_data()
|
| 357 |
except Exception as e:
|
| 358 |
-
|
| 359 |
-
|
| 360 |
-
logger.critical(traceback.format_exc())
|
| 361 |
-
msgBox = QtWidgets.QMessageBox()
|
| 362 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 363 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 364 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 365 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 366 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 367 |
-
msgBox.exec()
|
| 368 |
-
|
| 369 |
-
exit(-1)
|
| 370 |
-
|
| 371 |
#button trigger for sql settings
|
| 372 |
def update_sql_query_settings(self):
|
| 373 |
try:
|
| 374 |
-
self.sql_settings
|
| 375 |
self.sql_settings.show()
|
| 376 |
self.sql_settings.activateWindow()
|
| 377 |
except Exception as e:
|
| 378 |
-
|
| 379 |
-
|
| 380 |
-
logger.critical(traceback.format_exc())
|
| 381 |
-
msgBox = QtWidgets.QMessageBox()
|
| 382 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 383 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 384 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 385 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 386 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 387 |
-
msgBox.exec()
|
| 388 |
-
|
| 389 |
-
exit(-1)
|
| 390 |
-
|
| 391 |
#trigger for if sql line edit value has changed
|
| 392 |
def sql_row_count_value_changed(self):
|
| 393 |
try:
|
| 394 |
self.row_limit = int(self.sql_settings.row_count.text())
|
| 395 |
except Exception as e:
|
| 396 |
-
|
| 397 |
-
logger.critical(e)
|
| 398 |
-
logger.critical(traceback.format_exc())
|
| 399 |
pass
|
| 400 |
|
| 401 |
def get_data(self):
|
|
@@ -452,19 +282,8 @@ class Multitargeting(QtWidgets.QMainWindow):
|
|
| 452 |
self.cspr_file = self.organisms_to_files[str(self.organism_drop.currentText())][endos[0]][0]
|
| 453 |
self.db_file = self.organisms_to_files[str(self.organism_drop.currentText())][endos[0]][1]
|
| 454 |
except Exception as e:
|
| 455 |
-
|
| 456 |
-
|
| 457 |
-
logger.critical(traceback.format_exc())
|
| 458 |
-
msgBox = QtWidgets.QMessageBox()
|
| 459 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 460 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 461 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 462 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 463 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 464 |
-
msgBox.exec()
|
| 465 |
-
|
| 466 |
-
exit(-1)
|
| 467 |
-
|
| 468 |
def update_endos(self):
|
| 469 |
try:
|
| 470 |
#try to disconnect index changed signal on endo dropdown if there is one
|
|
@@ -478,26 +297,15 @@ class Multitargeting(QtWidgets.QMainWindow):
|
|
| 478 |
endos = self.organisms_to_endos[str(self.organism_drop.currentText())]
|
| 479 |
self.endo_drop.addItems(endos)
|
| 480 |
except Exception as e:
|
| 481 |
-
|
| 482 |
-
|
| 483 |
-
logger.critical(traceback.format_exc())
|
| 484 |
-
msgBox = QtWidgets.QMessageBox()
|
| 485 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 486 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 487 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 488 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 489 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 490 |
-
msgBox.exec()
|
| 491 |
-
|
| 492 |
-
exit(-1)
|
| 493 |
-
|
| 494 |
def make_graphs(self):
|
| 495 |
try:
|
| 496 |
self.cspr_file = self.organisms_to_files[str(self.organism_drop.currentText())][str(self.endo_drop.currentText())][0]
|
| 497 |
self.db_file = self.organisms_to_files[str(self.organism_drop.currentText())][str(self.endo_drop.currentText())][1]
|
| 498 |
|
| 499 |
self.loading_window.loading_bar.setValue(0)
|
| 500 |
-
self.loading_window
|
| 501 |
self.loading_window.show()
|
| 502 |
QtCore.QCoreApplication.processEvents()
|
| 503 |
self.chromo_length.clear()
|
|
@@ -521,18 +329,7 @@ class Multitargeting(QtWidgets.QMainWindow):
|
|
| 521 |
QtWidgets.QApplication.processEvents()
|
| 522 |
|
| 523 |
except Exception as e:
|
| 524 |
-
|
| 525 |
-
logger.critical(e)
|
| 526 |
-
logger.critical(traceback.format_exc())
|
| 527 |
-
msgBox = QtWidgets.QMessageBox()
|
| 528 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 529 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 530 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 531 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 532 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 533 |
-
msgBox.exec()
|
| 534 |
-
|
| 535 |
-
exit(-1)
|
| 536 |
|
| 537 |
#function to fill table in UI
|
| 538 |
def fill_table(self):
|
|
@@ -676,18 +473,7 @@ class Multitargeting(QtWidgets.QMainWindow):
|
|
| 676 |
#reconnect row trigger
|
| 677 |
self.table.itemSelectionChanged.connect(self.row_selection_trigger)
|
| 678 |
except Exception as e:
|
| 679 |
-
|
| 680 |
-
logger.critical(e)
|
| 681 |
-
logger.critical(traceback.format_exc())
|
| 682 |
-
msgBox = QtWidgets.QMessageBox()
|
| 683 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 684 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 685 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 686 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 687 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 688 |
-
msgBox.exec()
|
| 689 |
-
|
| 690 |
-
exit(-1)
|
| 691 |
|
| 692 |
#function for triggering graph updates when user selects row in table
|
| 693 |
def row_selection_trigger(self):
|
|
@@ -699,19 +485,8 @@ class Multitargeting(QtWidgets.QMainWindow):
|
|
| 699 |
self.fill_Chromo_Text(seed)
|
| 700 |
self.chro_bar_create(seed)
|
| 701 |
except Exception as e:
|
| 702 |
-
|
| 703 |
-
|
| 704 |
-
logger.critical(traceback.format_exc())
|
| 705 |
-
msgBox = QtWidgets.QMessageBox()
|
| 706 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 707 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 708 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 709 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 710 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 711 |
-
msgBox.exec()
|
| 712 |
-
|
| 713 |
-
exit(-1)
|
| 714 |
-
|
| 715 |
# sorting to table
|
| 716 |
def table_sorting(self, logicalIndex):
|
| 717 |
try:
|
|
@@ -721,18 +496,7 @@ class Multitargeting(QtWidgets.QMainWindow):
|
|
| 721 |
else:
|
| 722 |
self.table.sortItems(logicalIndex, QtCore.Qt.AscendingOrder)
|
| 723 |
except Exception as e:
|
| 724 |
-
|
| 725 |
-
logger.critical(e)
|
| 726 |
-
logger.critical(traceback.format_exc())
|
| 727 |
-
msgBox = QtWidgets.QMessageBox()
|
| 728 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 729 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 730 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 731 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 732 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 733 |
-
msgBox.exec()
|
| 734 |
-
|
| 735 |
-
exit(-1)
|
| 736 |
|
| 737 |
#fill in chromo bar visualization
|
| 738 |
def fill_Chromo_Text(self, seed):
|
|
@@ -844,18 +608,7 @@ class Multitargeting(QtWidgets.QMainWindow):
|
|
| 844 |
|
| 845 |
return False
|
| 846 |
except Exception as e:
|
| 847 |
-
|
| 848 |
-
logger.critical(e)
|
| 849 |
-
logger.critical(traceback.format_exc())
|
| 850 |
-
msgBox = QtWidgets.QMessageBox()
|
| 851 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 852 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 853 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 854 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 855 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 856 |
-
msgBox.exec()
|
| 857 |
-
|
| 858 |
-
exit(-1)
|
| 859 |
|
| 860 |
# creates bar graph num of repeats vs. chromosome
|
| 861 |
def chro_bar_create(self, seed):
|
|
@@ -898,18 +651,7 @@ class Multitargeting(QtWidgets.QMainWindow):
|
|
| 898 |
self.line_canvas.axes.tick_params(axis='both', which='major', labelsize=8)
|
| 899 |
self.line_canvas.draw()
|
| 900 |
except Exception as e:
|
| 901 |
-
|
| 902 |
-
logger.critical(e)
|
| 903 |
-
logger.critical(traceback.format_exc())
|
| 904 |
-
msgBox = QtWidgets.QMessageBox()
|
| 905 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 906 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 907 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 908 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 909 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 910 |
-
msgBox.exec()
|
| 911 |
-
|
| 912 |
-
exit(-1)
|
| 913 |
|
| 914 |
def bar_seeds_vs_repeats(self):
|
| 915 |
try:
|
|
@@ -943,19 +685,8 @@ class Multitargeting(QtWidgets.QMainWindow):
|
|
| 943 |
|
| 944 |
self.bar_bool = True
|
| 945 |
except Exception as e:
|
| 946 |
-
|
| 947 |
-
|
| 948 |
-
logger.critical(traceback.format_exc())
|
| 949 |
-
msgBox = QtWidgets.QMessageBox()
|
| 950 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 951 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 952 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 953 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 954 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 955 |
-
msgBox.exec()
|
| 956 |
-
|
| 957 |
-
exit(-1)
|
| 958 |
-
|
| 959 |
# # plots the repeats per ID number graph as line graph
|
| 960 |
def plot_repeats_vs_seeds(self):
|
| 961 |
try:
|
|
@@ -994,19 +725,8 @@ class Multitargeting(QtWidgets.QMainWindow):
|
|
| 994 |
self.line_bool = True
|
| 995 |
self.line_canvas.draw()
|
| 996 |
except Exception as e:
|
| 997 |
-
|
| 998 |
-
|
| 999 |
-
logger.critical(traceback.format_exc())
|
| 1000 |
-
msgBox = QtWidgets.QMessageBox()
|
| 1001 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 1002 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 1003 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 1004 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 1005 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 1006 |
-
msgBox.exec()
|
| 1007 |
-
|
| 1008 |
-
exit(-1)
|
| 1009 |
-
|
| 1010 |
def seed_chromo_changed(self):
|
| 1011 |
try:
|
| 1012 |
self.loading_window.loading_bar.setValue(5)
|
|
@@ -1017,19 +737,8 @@ class Multitargeting(QtWidgets.QMainWindow):
|
|
| 1017 |
self.loading_window.loading_bar.setValue(100)
|
| 1018 |
self.loading_window.hide()
|
| 1019 |
except Exception as e:
|
| 1020 |
-
|
| 1021 |
-
|
| 1022 |
-
logger.critical(traceback.format_exc())
|
| 1023 |
-
msgBox = QtWidgets.QMessageBox()
|
| 1024 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 1025 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 1026 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 1027 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 1028 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 1029 |
-
msgBox.exec()
|
| 1030 |
-
|
| 1031 |
-
exit(-1)
|
| 1032 |
-
|
| 1033 |
#connects to go back button in bottom left to switch back to the main CASPER window
|
| 1034 |
def go_back(self):
|
| 1035 |
try:
|
|
@@ -1038,19 +747,8 @@ class Multitargeting(QtWidgets.QMainWindow):
|
|
| 1038 |
GlobalSettings.mainWindow.show()
|
| 1039 |
self.hide()
|
| 1040 |
except Exception as e:
|
| 1041 |
-
|
| 1042 |
-
|
| 1043 |
-
logger.critical(traceback.format_exc())
|
| 1044 |
-
msgBox = QtWidgets.QMessageBox()
|
| 1045 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 1046 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 1047 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 1048 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 1049 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 1050 |
-
msgBox.exec()
|
| 1051 |
-
|
| 1052 |
-
exit(-1)
|
| 1053 |
-
|
| 1054 |
# this function calls the closingWindow class.
|
| 1055 |
def closeEvent(self, event):
|
| 1056 |
try:
|
|
@@ -1059,132 +757,22 @@ class Multitargeting(QtWidgets.QMainWindow):
|
|
| 1059 |
self.multitargeting_statistics.hide()
|
| 1060 |
event.accept()
|
| 1061 |
except Exception as e:
|
| 1062 |
-
|
| 1063 |
-
logger.critical(e)
|
| 1064 |
-
logger.critical(traceback.format_exc())
|
| 1065 |
-
msgBox = QtWidgets.QMessageBox()
|
| 1066 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 1067 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 1068 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 1069 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 1070 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 1071 |
-
msgBox.exec()
|
| 1072 |
-
|
| 1073 |
-
exit(-1)
|
| 1074 |
-
|
| 1075 |
|
| 1076 |
class loading_window(QtWidgets.QMainWindow):
|
| 1077 |
def __init__(self):
|
| 1078 |
try:
|
| 1079 |
super(loading_window, self).__init__()
|
| 1080 |
-
uic.loadUi(GlobalSettings.appdir + "loading_data_form.ui", self)
|
| 1081 |
self.setWindowIcon(Qt.QIcon(GlobalSettings.appdir + "cas9image.ico"))
|
| 1082 |
self.loading_bar.setValue(0)
|
| 1083 |
self.setWindowTitle("Loading Data")
|
| 1084 |
|
| 1085 |
-
|
| 1086 |
-
self.scaleUI()
|
| 1087 |
-
|
| 1088 |
-
except Exception as e:
|
| 1089 |
-
logger.critical("Error initializing loading_window class in multi-targeting.")
|
| 1090 |
-
logger.critical(e)
|
| 1091 |
-
logger.critical(traceback.format_exc())
|
| 1092 |
-
msgBox = QtWidgets.QMessageBox()
|
| 1093 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 1094 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 1095 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 1096 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 1097 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 1098 |
-
msgBox.exec()
|
| 1099 |
-
|
| 1100 |
-
exit(-1)
|
| 1101 |
-
|
| 1102 |
-
def scaleUI(self):
|
| 1103 |
-
try:
|
| 1104 |
-
self.repaint()
|
| 1105 |
-
QtWidgets.QApplication.processEvents()
|
| 1106 |
-
|
| 1107 |
-
screen = self.screen()
|
| 1108 |
-
dpi = screen.physicalDotsPerInch()
|
| 1109 |
-
width = screen.geometry().width()
|
| 1110 |
-
height = screen.geometry().height()
|
| 1111 |
-
|
| 1112 |
-
# font scaling
|
| 1113 |
-
# 14px is used for 92 dpi
|
| 1114 |
-
fontSize = 12
|
| 1115 |
-
self.centralWidget().setStyleSheet("font: " + str(fontSize) + "pt 'Arial';")
|
| 1116 |
|
| 1117 |
-
self.adjustSize()
|
| 1118 |
-
|
| 1119 |
-
currentWidth = self.size().width()
|
| 1120 |
-
currentHeight = self.size().height()
|
| 1121 |
-
|
| 1122 |
-
# scale/center window
|
| 1123 |
-
scaledWidth = int((width * 450) / 1920)
|
| 1124 |
-
scaledHeight = int((height * 125) / 1080)
|
| 1125 |
-
|
| 1126 |
-
if scaledHeight < currentHeight:
|
| 1127 |
-
scaledHeight = currentHeight
|
| 1128 |
-
if scaledWidth < currentWidth:
|
| 1129 |
-
scaledWidth = currentWidth
|
| 1130 |
-
|
| 1131 |
-
screen = QtWidgets.QApplication.desktop().screenNumber(QtWidgets.QApplication.desktop().cursor().pos())
|
| 1132 |
-
centerPoint = QtWidgets.QApplication.desktop().screenGeometry(screen).center()
|
| 1133 |
-
x = centerPoint.x()
|
| 1134 |
-
y = centerPoint.y()
|
| 1135 |
-
x = x - (math.ceil(scaledWidth / 2))
|
| 1136 |
-
y = y - (math.ceil(scaledHeight / 2))
|
| 1137 |
-
self.setGeometry(x, y, scaledWidth, scaledHeight)
|
| 1138 |
-
|
| 1139 |
-
self.repaint()
|
| 1140 |
-
QtWidgets.QApplication.processEvents()
|
| 1141 |
except Exception as e:
|
| 1142 |
-
|
| 1143 |
-
|
| 1144 |
-
logger.critical(traceback.format_exc())
|
| 1145 |
-
msgBox = QtWidgets.QMessageBox()
|
| 1146 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 1147 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 1148 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 1149 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 1150 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 1151 |
-
msgBox.exec()
|
| 1152 |
-
|
| 1153 |
-
exit(-1)
|
| 1154 |
-
|
| 1155 |
-
def centerUI(self):
|
| 1156 |
-
try:
|
| 1157 |
-
self.repaint()
|
| 1158 |
-
QtWidgets.QApplication.processEvents()
|
| 1159 |
-
|
| 1160 |
-
# center window on current screen
|
| 1161 |
-
width = self.width()
|
| 1162 |
-
height = self.height()
|
| 1163 |
-
screen = QtWidgets.QApplication.desktop().screenNumber(QtWidgets.QApplication.desktop().cursor().pos())
|
| 1164 |
-
centerPoint = QtWidgets.QApplication.desktop().screenGeometry(screen).center()
|
| 1165 |
-
x = centerPoint.x()
|
| 1166 |
-
y = centerPoint.y()
|
| 1167 |
-
x = x - (math.ceil(width / 2))
|
| 1168 |
-
y = y - (math.ceil(height / 2))
|
| 1169 |
-
self.setGeometry(x, y, width, height)
|
| 1170 |
-
|
| 1171 |
-
self.repaint()
|
| 1172 |
-
QtWidgets.QApplication.processEvents()
|
| 1173 |
-
except Exception as e:
|
| 1174 |
-
logger.critical("Error in centerUI() in loading window in multitargeting.")
|
| 1175 |
-
logger.critical(e)
|
| 1176 |
-
logger.critical(traceback.format_exc())
|
| 1177 |
-
msgBox = QtWidgets.QMessageBox()
|
| 1178 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 1179 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 1180 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 1181 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 1182 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 1183 |
-
msgBox.exec()
|
| 1184 |
-
|
| 1185 |
-
exit(-1)
|
| 1186 |
-
|
| 1187 |
-
|
| 1188 |
class MplCanvas(FigureCanvasQTAgg):
|
| 1189 |
def __init__(self, parent=None, width=5, height=4, dpi=100):
|
| 1190 |
try:
|
|
@@ -1207,252 +795,31 @@ class MplCanvas(FigureCanvasQTAgg):
|
|
| 1207 |
# QtWidgets.QSizePolicy.Expanding)
|
| 1208 |
# FigureCanvasQTAgg.updateGeometry(self)
|
| 1209 |
except Exception as e:
|
| 1210 |
-
|
| 1211 |
-
logger.critical(e)
|
| 1212 |
-
logger.critical(traceback.format_exc())
|
| 1213 |
-
msgBox = QtWidgets.QMessageBox()
|
| 1214 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 1215 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 1216 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 1217 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 1218 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 1219 |
-
msgBox.exec()
|
| 1220 |
-
|
| 1221 |
-
exit(-1)
|
| 1222 |
-
|
| 1223 |
|
| 1224 |
class Multitargeting_Statistics(QtWidgets.QMainWindow):
|
| 1225 |
def __init__(self, parent=None):
|
| 1226 |
try:
|
| 1227 |
super(Multitargeting_Statistics, self).__init__(parent)
|
| 1228 |
-
uic.loadUi(GlobalSettings.appdir + 'multitargeting_stats.ui', self)
|
| 1229 |
self.setWindowIcon(Qt.QIcon(GlobalSettings.appdir + "cas9image.ico"))
|
| 1230 |
self.setWindowTitle("Statistics")
|
| 1231 |
|
| 1232 |
-
|
| 1233 |
-
self.scaleUI()
|
| 1234 |
-
|
| 1235 |
-
except Exception as e:
|
| 1236 |
-
logger.critical("Error initializing Multitargeting_Statistics class in multi-targeting.")
|
| 1237 |
-
logger.critical(e)
|
| 1238 |
-
logger.critical(traceback.format_exc())
|
| 1239 |
-
msgBox = QtWidgets.QMessageBox()
|
| 1240 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 1241 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 1242 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 1243 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 1244 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 1245 |
-
msgBox.exec()
|
| 1246 |
-
|
| 1247 |
-
exit(-1)
|
| 1248 |
-
|
| 1249 |
-
#scale UI based on current screen
|
| 1250 |
-
def scaleUI(self):
|
| 1251 |
-
try:
|
| 1252 |
-
self.repaint()
|
| 1253 |
-
QtWidgets.QApplication.processEvents()
|
| 1254 |
-
|
| 1255 |
-
screen = self.screen()
|
| 1256 |
-
dpi = screen.physicalDotsPerInch()
|
| 1257 |
-
width = screen.geometry().width()
|
| 1258 |
-
height = screen.geometry().height()
|
| 1259 |
-
|
| 1260 |
-
# font scaling
|
| 1261 |
-
# 16px is used for 92 dpi / 1920x1080
|
| 1262 |
-
fontSize = 12
|
| 1263 |
-
self.fontSize = fontSize
|
| 1264 |
-
self.centralWidget().setStyleSheet("font: " + str(fontSize) + "pt 'Arial';")
|
| 1265 |
-
|
| 1266 |
-
# CASPER header scaling
|
| 1267 |
-
fontSize = 20
|
| 1268 |
-
self.title.setStyleSheet("font: bold " + str(fontSize) + "pt 'Arial';")
|
| 1269 |
-
|
| 1270 |
-
self.adjustSize()
|
| 1271 |
-
|
| 1272 |
-
currentWidth = self.size().width()
|
| 1273 |
-
currentHeight = self.size().height()
|
| 1274 |
-
|
| 1275 |
-
# window scaling
|
| 1276 |
-
scaledWidth = int((width * 275) / 1920)
|
| 1277 |
-
scaledHeight = int((height * 185) / 1080)
|
| 1278 |
-
|
| 1279 |
-
if scaledHeight < currentHeight:
|
| 1280 |
-
scaledHeight = currentHeight
|
| 1281 |
-
if scaledWidth < currentWidth:
|
| 1282 |
-
scaledWidth = currentWidth
|
| 1283 |
-
|
| 1284 |
-
screen = QtWidgets.QApplication.desktop().screenNumber(QtWidgets.QApplication.desktop().cursor().pos())
|
| 1285 |
-
centerPoint = QtWidgets.QApplication.desktop().screenGeometry(screen).center()
|
| 1286 |
-
x = centerPoint.x()
|
| 1287 |
-
y = centerPoint.y()
|
| 1288 |
-
x = x - (math.ceil(scaledWidth / 2))
|
| 1289 |
-
y = y - (math.ceil(scaledHeight / 2))
|
| 1290 |
-
self.setGeometry(x, y, scaledWidth, scaledHeight)
|
| 1291 |
-
|
| 1292 |
-
self.repaint()
|
| 1293 |
-
QtWidgets.QApplication.processEvents()
|
| 1294 |
-
except Exception as e:
|
| 1295 |
-
logger.critical("Error in scaleUI() in multitargeting statistics in multitargeting.")
|
| 1296 |
-
logger.critical(e)
|
| 1297 |
-
logger.critical(traceback.format_exc())
|
| 1298 |
-
msgBox = QtWidgets.QMessageBox()
|
| 1299 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 1300 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 1301 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 1302 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 1303 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 1304 |
-
msgBox.exec()
|
| 1305 |
-
|
| 1306 |
-
exit(-1)
|
| 1307 |
-
|
| 1308 |
-
# center UI on current screen
|
| 1309 |
-
def centerUI(self):
|
| 1310 |
-
try:
|
| 1311 |
-
self.repaint()
|
| 1312 |
-
QtWidgets.QApplication.processEvents()
|
| 1313 |
-
|
| 1314 |
-
# center window on current screen
|
| 1315 |
-
width = self.width()
|
| 1316 |
-
height = self.height()
|
| 1317 |
-
screen = QtWidgets.QApplication.desktop().screenNumber(QtWidgets.QApplication.desktop().cursor().pos())
|
| 1318 |
-
centerPoint = QtWidgets.QApplication.desktop().screenGeometry(screen).center()
|
| 1319 |
-
x = centerPoint.x()
|
| 1320 |
-
y = centerPoint.y()
|
| 1321 |
-
x = x - (math.ceil(width / 2))
|
| 1322 |
-
y = y - (math.ceil(height / 2))
|
| 1323 |
-
self.setGeometry(x, y, width, height)
|
| 1324 |
|
| 1325 |
-
self.repaint()
|
| 1326 |
-
QtWidgets.QApplication.processEvents()
|
| 1327 |
except Exception as e:
|
| 1328 |
-
|
| 1329 |
-
|
| 1330 |
-
logger.critical(traceback.format_exc())
|
| 1331 |
-
msgBox = QtWidgets.QMessageBox()
|
| 1332 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 1333 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 1334 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 1335 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 1336 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 1337 |
-
msgBox.exec()
|
| 1338 |
-
|
| 1339 |
-
exit(-1)
|
| 1340 |
-
|
| 1341 |
-
|
| 1342 |
class sql_query_settings(QtWidgets.QMainWindow):
|
| 1343 |
def __init__(self):
|
| 1344 |
try:
|
| 1345 |
super(sql_query_settings, self).__init__()
|
| 1346 |
-
uic.loadUi(GlobalSettings.appdir + "multitargeting_sql_settings.ui", self)
|
| 1347 |
self.setWindowTitle("SQL Settings")
|
| 1348 |
self.setWindowIcon(Qt.QIcon(GlobalSettings.appdir + "cas9image.ico"))
|
| 1349 |
self.row_count.setValidator(QtGui.QIntValidator())
|
| 1350 |
|
| 1351 |
-
|
| 1352 |
-
self.scaleUI()
|
| 1353 |
-
|
| 1354 |
-
except Exception as e:
|
| 1355 |
-
logger.critical("Error initializing sql_query_settings class in multi-targeting.")
|
| 1356 |
-
logger.critical(e)
|
| 1357 |
-
logger.critical(traceback.format_exc())
|
| 1358 |
-
msgBox = QtWidgets.QMessageBox()
|
| 1359 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 1360 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 1361 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 1362 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 1363 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 1364 |
-
msgBox.exec()
|
| 1365 |
-
|
| 1366 |
-
exit(-1)
|
| 1367 |
-
|
| 1368 |
-
#scale UI based on current screen
|
| 1369 |
-
def scaleUI(self):
|
| 1370 |
-
try:
|
| 1371 |
-
self.repaint()
|
| 1372 |
-
QtWidgets.QApplication.processEvents()
|
| 1373 |
-
|
| 1374 |
-
screen = self.screen()
|
| 1375 |
-
dpi = screen.physicalDotsPerInch()
|
| 1376 |
-
width = screen.geometry().width()
|
| 1377 |
-
height = screen.geometry().height()
|
| 1378 |
-
|
| 1379 |
-
# font scaling
|
| 1380 |
-
# 16px is used for 92 dpi / 1920x1080
|
| 1381 |
-
fontSize = 12
|
| 1382 |
-
self.fontSize = fontSize
|
| 1383 |
-
self.centralWidget().setStyleSheet("font: " + str(fontSize) + "pt 'Arial';")
|
| 1384 |
-
|
| 1385 |
-
# CASPER header scaling
|
| 1386 |
-
fontSize = 20
|
| 1387 |
-
self.title.setStyleSheet("font: bold " + str(fontSize) + "pt 'Arial';")
|
| 1388 |
|
| 1389 |
-
self.adjustSize()
|
| 1390 |
-
|
| 1391 |
-
currentWidth = self.size().width()
|
| 1392 |
-
currentHeight = self.size().height()
|
| 1393 |
-
|
| 1394 |
-
# window scaling
|
| 1395 |
-
scaledWidth = int((width * 375) / 1920)
|
| 1396 |
-
scaledHeight = int((height * 140) / 1080)
|
| 1397 |
-
|
| 1398 |
-
if scaledHeight < currentHeight:
|
| 1399 |
-
scaledHeight = currentHeight
|
| 1400 |
-
if scaledWidth < currentWidth:
|
| 1401 |
-
scaledWidth = currentWidth
|
| 1402 |
-
|
| 1403 |
-
screen = QtWidgets.QApplication.desktop().screenNumber(QtWidgets.QApplication.desktop().cursor().pos())
|
| 1404 |
-
centerPoint = QtWidgets.QApplication.desktop().screenGeometry(screen).center()
|
| 1405 |
-
x = centerPoint.x()
|
| 1406 |
-
y = centerPoint.y()
|
| 1407 |
-
x = x - (math.ceil(scaledWidth / 2))
|
| 1408 |
-
y = y - (math.ceil(scaledHeight / 2))
|
| 1409 |
-
self.setGeometry(x, y, scaledWidth, scaledHeight)
|
| 1410 |
-
|
| 1411 |
-
self.repaint()
|
| 1412 |
-
QtWidgets.QApplication.processEvents()
|
| 1413 |
-
except Exception as e:
|
| 1414 |
-
logger.critical("Error in scaleUI() in sql settings in multitargeting.")
|
| 1415 |
-
logger.critical(e)
|
| 1416 |
-
logger.critical(traceback.format_exc())
|
| 1417 |
-
msgBox = QtWidgets.QMessageBox()
|
| 1418 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 1419 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 1420 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 1421 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 1422 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 1423 |
-
msgBox.exec()
|
| 1424 |
-
|
| 1425 |
-
exit(-1)
|
| 1426 |
-
|
| 1427 |
-
#center UI on current screen
|
| 1428 |
-
def centerUI(self):
|
| 1429 |
-
try:
|
| 1430 |
-
self.repaint()
|
| 1431 |
-
QtWidgets.QApplication.processEvents()
|
| 1432 |
-
|
| 1433 |
-
# center window on current screen
|
| 1434 |
-
width = self.width()
|
| 1435 |
-
height = self.height()
|
| 1436 |
-
screen = QtWidgets.QApplication.desktop().screenNumber(QtWidgets.QApplication.desktop().cursor().pos())
|
| 1437 |
-
centerPoint = QtWidgets.QApplication.desktop().screenGeometry(screen).center()
|
| 1438 |
-
x = centerPoint.x()
|
| 1439 |
-
y = centerPoint.y()
|
| 1440 |
-
x = x - (math.ceil(width / 2))
|
| 1441 |
-
y = y - (math.ceil(height / 2))
|
| 1442 |
-
self.setGeometry(x, y, width, height)
|
| 1443 |
-
|
| 1444 |
-
self.repaint()
|
| 1445 |
-
QtWidgets.QApplication.processEvents()
|
| 1446 |
except Exception as e:
|
| 1447 |
-
|
| 1448 |
-
logger.critical(e)
|
| 1449 |
-
logger.critical(traceback.format_exc())
|
| 1450 |
-
msgBox = QtWidgets.QMessageBox()
|
| 1451 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 1452 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 1453 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 1454 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 1455 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 1456 |
-
msgBox.exec()
|
| 1457 |
-
|
| 1458 |
-
exit(-1)
|
|
|
|
| 1 |
from PyQt5 import QtWidgets, Qt, QtGui, QtCore, uic
|
| 2 |
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg
|
| 3 |
from matplotlib.figure import Figure
|
| 4 |
+
import models.GlobalSettings as GlobalSettings
|
| 5 |
import matplotlib
|
| 6 |
+
from utils.Algorithms import SeqTranslate
|
| 7 |
+
from models.CSPRparser import CSPRparser
|
| 8 |
from matplotlib.ticker import MaxNLocator
|
| 9 |
import os
|
| 10 |
import sqlite3
|
|
|
|
| 18 |
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
|
| 19 |
from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolbar
|
| 20 |
import matplotlib.pyplot as plt
|
| 21 |
+
from utils.ui import show_message, show_error, scale_ui, center_ui
|
| 22 |
+
|
| 23 |
logger = GlobalSettings.logger
|
| 24 |
|
| 25 |
class Multitargeting(QtWidgets.QMainWindow):
|
|
|
|
| 27 |
try:
|
| 28 |
self.count = 0
|
| 29 |
super(Multitargeting, self).__init__()
|
| 30 |
+
uic.loadUi(GlobalSettings.appdir + 'ui/mt.ui', self)
|
| 31 |
self.setWindowIcon(Qt.QIcon(GlobalSettings.appdir + "cas9image.ico"))
|
| 32 |
self.multitargeting_statistics = Multitargeting_Statistics()
|
| 33 |
|
|
|
|
| 85 |
self.selectAll.stateChanged.connect(self.select_all)
|
| 86 |
self.selectAll.setEnabled(False)
|
| 87 |
|
| 88 |
+
# go back to main window
|
| 89 |
self.back_button.clicked.connect(self.go_back)
|
| 90 |
|
| 91 |
# Statistics storage variables
|
|
|
|
| 98 |
self.bar_coords = []
|
| 99 |
self.seed_id_seq_pair = {}
|
| 100 |
|
|
|
|
| 101 |
self.parser = CSPRparser("")
|
| 102 |
|
| 103 |
self.ready_chromo_min_max = True
|
| 104 |
self.ready_chromo_make_graph = True
|
| 105 |
self.info_path = os.getcwd()
|
| 106 |
|
|
|
|
| 107 |
self.scene = QtWidgets.QGraphicsScene()
|
| 108 |
self.scene2 = QtWidgets.QGraphicsScene()
|
| 109 |
self.graphicsView_2.setScene(self.scene2)
|
|
|
|
| 118 |
self.sql_settings = sql_query_settings()
|
| 119 |
self.sql_settings.row_count.textChanged.connect(self.sql_row_count_value_changed)
|
| 120 |
|
|
|
|
| 121 |
self.first_show = True
|
| 122 |
+
scale_ui(self, custom_scale_width=1400, custom_scale_height=900)
|
| 123 |
+
|
| 124 |
+
dpi = self.screen().physicalDotsPerInch()
|
| 125 |
+
self.dpi = dpi
|
| 126 |
|
| 127 |
except Exception as e:
|
| 128 |
+
show_error("Error initializing Multi-targeting.", e)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 129 |
|
| 130 |
def select_all(self):
|
| 131 |
try:
|
|
|
|
| 134 |
else:
|
| 135 |
self.table.clearSelection()
|
| 136 |
except Exception as e:
|
| 137 |
+
show_error("Error in selectAll() in multitargeting.", e)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 138 |
|
| 139 |
def export_tool(self):
|
| 140 |
try:
|
| 141 |
select_items = self.table.selectedItems()
|
| 142 |
if len(select_items) <= 0:
|
| 143 |
+
show_message(
|
| 144 |
+
fontSize=12,
|
| 145 |
+
icon=QtWidgets.QMessageBox.Icon.Critical,
|
| 146 |
+
title="No targets were highlighted",
|
| 147 |
+
message="Please highlight the targets you want to be exported to a CSV File!"
|
| 148 |
+
)
|
|
|
|
|
|
|
| 149 |
return
|
| 150 |
GlobalSettings.mainWindow.export_tool_window.launch(select_items,"mt")
|
| 151 |
except Exception as e:
|
| 152 |
+
show_error("Error in export_tool() in multi-targeting.", e)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 153 |
|
| 154 |
def show_statistics(self):
|
| 155 |
try:
|
| 156 |
if (self.line_bool and self.bar_bool):
|
| 157 |
+
center_ui(self.multitargeting_statistics)
|
| 158 |
self.multitargeting_statistics.show()
|
| 159 |
self.multitargeting_statistics.activateWindow()
|
| 160 |
else:
|
| 161 |
+
show_message(
|
| 162 |
+
fontSize=12,
|
| 163 |
+
icon=QtWidgets.QMessageBox.Icon.Critical,
|
| 164 |
+
title="No analysis run.",
|
| 165 |
+
message="Multitargeting Analysis must be performed before viewing statistics.\n\nSelect an organism and endonuclease and click 'Analyze' then try again."
|
| 166 |
+
)
|
|
|
|
|
|
|
| 167 |
return True
|
| 168 |
except Exception as e:
|
| 169 |
+
show_error("Error in show_statistics() in multi-targeting.", e)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 170 |
|
| 171 |
#event handler to show details of targets in chromosome viewer while hovering over canvases
|
| 172 |
def chromosome_event_handler(self, event):
|
|
|
|
| 203 |
text.setFont(font)
|
| 204 |
|
| 205 |
except Exception as e:
|
| 206 |
+
show_error("Error in event_data() in multi-targeting.", e)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 207 |
|
| 208 |
def launch(self):
|
| 209 |
try:
|
| 210 |
self.get_data()
|
| 211 |
except Exception as e:
|
| 212 |
+
show_error("Error in launch() in multi-targeting.", e)
|
| 213 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 214 |
#button trigger for sql settings
|
| 215 |
def update_sql_query_settings(self):
|
| 216 |
try:
|
| 217 |
+
center_ui(self.sql_settings)
|
| 218 |
self.sql_settings.show()
|
| 219 |
self.sql_settings.activateWindow()
|
| 220 |
except Exception as e:
|
| 221 |
+
show_error("Error in update_sql_query_settings() in multi-targeting.", e)
|
| 222 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 223 |
#trigger for if sql line edit value has changed
|
| 224 |
def sql_row_count_value_changed(self):
|
| 225 |
try:
|
| 226 |
self.row_limit = int(self.sql_settings.row_count.text())
|
| 227 |
except Exception as e:
|
| 228 |
+
show_error("Error in sql_row_count_value_changed() in multi-targeting.", e)
|
|
|
|
|
|
|
| 229 |
pass
|
| 230 |
|
| 231 |
def get_data(self):
|
|
|
|
| 282 |
self.cspr_file = self.organisms_to_files[str(self.organism_drop.currentText())][endos[0]][0]
|
| 283 |
self.db_file = self.organisms_to_files[str(self.organism_drop.currentText())][endos[0]][1]
|
| 284 |
except Exception as e:
|
| 285 |
+
show_error("Error in get_data() in multi-targeting.", e)
|
| 286 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 287 |
def update_endos(self):
|
| 288 |
try:
|
| 289 |
#try to disconnect index changed signal on endo dropdown if there is one
|
|
|
|
| 297 |
endos = self.organisms_to_endos[str(self.organism_drop.currentText())]
|
| 298 |
self.endo_drop.addItems(endos)
|
| 299 |
except Exception as e:
|
| 300 |
+
show_error("Error in update_endos() in multi-targeting.", e)
|
| 301 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 302 |
def make_graphs(self):
|
| 303 |
try:
|
| 304 |
self.cspr_file = self.organisms_to_files[str(self.organism_drop.currentText())][str(self.endo_drop.currentText())][0]
|
| 305 |
self.db_file = self.organisms_to_files[str(self.organism_drop.currentText())][str(self.endo_drop.currentText())][1]
|
| 306 |
|
| 307 |
self.loading_window.loading_bar.setValue(0)
|
| 308 |
+
center_ui(self.loading_window)
|
| 309 |
self.loading_window.show()
|
| 310 |
QtCore.QCoreApplication.processEvents()
|
| 311 |
self.chromo_length.clear()
|
|
|
|
| 329 |
QtWidgets.QApplication.processEvents()
|
| 330 |
|
| 331 |
except Exception as e:
|
| 332 |
+
show_error("Error in make_graphs() in multi-targeting.", e)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 333 |
|
| 334 |
#function to fill table in UI
|
| 335 |
def fill_table(self):
|
|
|
|
| 473 |
#reconnect row trigger
|
| 474 |
self.table.itemSelectionChanged.connect(self.row_selection_trigger)
|
| 475 |
except Exception as e:
|
| 476 |
+
show_error("Error in fill_table() in multi-targeting.", e)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 477 |
|
| 478 |
#function for triggering graph updates when user selects row in table
|
| 479 |
def row_selection_trigger(self):
|
|
|
|
| 485 |
self.fill_Chromo_Text(seed)
|
| 486 |
self.chro_bar_create(seed)
|
| 487 |
except Exception as e:
|
| 488 |
+
show_error("Error in row_selection_trigger() in multi-targeting.", e)
|
| 489 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 490 |
# sorting to table
|
| 491 |
def table_sorting(self, logicalIndex):
|
| 492 |
try:
|
|
|
|
| 496 |
else:
|
| 497 |
self.table.sortItems(logicalIndex, QtCore.Qt.AscendingOrder)
|
| 498 |
except Exception as e:
|
| 499 |
+
show_error("Error in table_sorting() in multi-targeting.", e)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 500 |
|
| 501 |
#fill in chromo bar visualization
|
| 502 |
def fill_Chromo_Text(self, seed):
|
|
|
|
| 608 |
|
| 609 |
return False
|
| 610 |
except Exception as e:
|
| 611 |
+
show_error("Error in fill_Chromo_text() in multi-targeting.", e)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 612 |
|
| 613 |
# creates bar graph num of repeats vs. chromosome
|
| 614 |
def chro_bar_create(self, seed):
|
|
|
|
| 651 |
self.line_canvas.axes.tick_params(axis='both', which='major', labelsize=8)
|
| 652 |
self.line_canvas.draw()
|
| 653 |
except Exception as e:
|
| 654 |
+
show_error("Error in chro_bar_create() in multi-targeting.", e)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 655 |
|
| 656 |
def bar_seeds_vs_repeats(self):
|
| 657 |
try:
|
|
|
|
| 685 |
|
| 686 |
self.bar_bool = True
|
| 687 |
except Exception as e:
|
| 688 |
+
show_error("Error in bar_seeds_vs_repeats() in multi-targeting.", e)
|
| 689 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 690 |
# # plots the repeats per ID number graph as line graph
|
| 691 |
def plot_repeats_vs_seeds(self):
|
| 692 |
try:
|
|
|
|
| 725 |
self.line_bool = True
|
| 726 |
self.line_canvas.draw()
|
| 727 |
except Exception as e:
|
| 728 |
+
show_error("Error in plot_repeats_vs_seeds() in multi-targeting.", e)
|
| 729 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 730 |
def seed_chromo_changed(self):
|
| 731 |
try:
|
| 732 |
self.loading_window.loading_bar.setValue(5)
|
|
|
|
| 737 |
self.loading_window.loading_bar.setValue(100)
|
| 738 |
self.loading_window.hide()
|
| 739 |
except Exception as e:
|
| 740 |
+
show_error("Error in seed_chromo_changed() in multi-targeting.", e)
|
| 741 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 742 |
#connects to go back button in bottom left to switch back to the main CASPER window
|
| 743 |
def go_back(self):
|
| 744 |
try:
|
|
|
|
| 747 |
GlobalSettings.mainWindow.show()
|
| 748 |
self.hide()
|
| 749 |
except Exception as e:
|
| 750 |
+
show_error("Error in go_back() in multi-targeting.", e)
|
| 751 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 752 |
# this function calls the closingWindow class.
|
| 753 |
def closeEvent(self, event):
|
| 754 |
try:
|
|
|
|
| 757 |
self.multitargeting_statistics.hide()
|
| 758 |
event.accept()
|
| 759 |
except Exception as e:
|
| 760 |
+
show_error("Error in closeEvent() in multi-targeting.", e)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 761 |
|
| 762 |
class loading_window(QtWidgets.QMainWindow):
|
| 763 |
def __init__(self):
|
| 764 |
try:
|
| 765 |
super(loading_window, self).__init__()
|
| 766 |
+
uic.loadUi(GlobalSettings.appdir + "ui/loading_data_form.ui", self)
|
| 767 |
self.setWindowIcon(Qt.QIcon(GlobalSettings.appdir + "cas9image.ico"))
|
| 768 |
self.loading_bar.setValue(0)
|
| 769 |
self.setWindowTitle("Loading Data")
|
| 770 |
|
| 771 |
+
scale_ui(self, custom_scale_width=450, custom_scale_height=125)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 772 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 773 |
except Exception as e:
|
| 774 |
+
show_error("Error initializing loading_window class in multi-targeting.", e)
|
| 775 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 776 |
class MplCanvas(FigureCanvasQTAgg):
|
| 777 |
def __init__(self, parent=None, width=5, height=4, dpi=100):
|
| 778 |
try:
|
|
|
|
| 795 |
# QtWidgets.QSizePolicy.Expanding)
|
| 796 |
# FigureCanvasQTAgg.updateGeometry(self)
|
| 797 |
except Exception as e:
|
| 798 |
+
show_error("Error initializing MplCanvas class in multi-targeting.", e)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 799 |
|
| 800 |
class Multitargeting_Statistics(QtWidgets.QMainWindow):
|
| 801 |
def __init__(self, parent=None):
|
| 802 |
try:
|
| 803 |
super(Multitargeting_Statistics, self).__init__(parent)
|
| 804 |
+
uic.loadUi(GlobalSettings.appdir + 'ui/multitargeting_stats.ui', self)
|
| 805 |
self.setWindowIcon(Qt.QIcon(GlobalSettings.appdir + "cas9image.ico"))
|
| 806 |
self.setWindowTitle("Statistics")
|
| 807 |
|
| 808 |
+
scale_ui(self, custom_scale_width=275, custom_scale_height=185)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 809 |
|
|
|
|
|
|
|
| 810 |
except Exception as e:
|
| 811 |
+
show_error("Error initializing Multitargeting_Statistics class in multi-targeting.", e)
|
| 812 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 813 |
class sql_query_settings(QtWidgets.QMainWindow):
|
| 814 |
def __init__(self):
|
| 815 |
try:
|
| 816 |
super(sql_query_settings, self).__init__()
|
| 817 |
+
uic.loadUi(GlobalSettings.appdir + "ui/multitargeting_sql_settings.ui", self)
|
| 818 |
self.setWindowTitle("SQL Settings")
|
| 819 |
self.setWindowIcon(Qt.QIcon(GlobalSettings.appdir + "cas9image.ico"))
|
| 820 |
self.row_count.setValidator(QtGui.QIntValidator())
|
| 821 |
|
| 822 |
+
scale_ui(self, custom_scale_width=375, custom_scale_height=140)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 823 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 824 |
except Exception as e:
|
| 825 |
+
show_error("Error initializing sql_query_settings class in multi-targeting.", e)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@@ -0,0 +1,915 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from Bio import Entrez
|
| 2 |
+
from bs4 import BeautifulSoup
|
| 3 |
+
from PyQt5 import QtWidgets, Qt, QtCore, uic
|
| 4 |
+
from ftplib import FTP
|
| 5 |
+
import gzip
|
| 6 |
+
import pandas as pd
|
| 7 |
+
import shutil
|
| 8 |
+
import os, time
|
| 9 |
+
import ssl
|
| 10 |
+
import models.GlobalSettings as GlobalSettings
|
| 11 |
+
import platform
|
| 12 |
+
import traceback
|
| 13 |
+
import math
|
| 14 |
+
from utils.ui import show_message, show_error, scale_ui, center_ui
|
| 15 |
+
|
| 16 |
+
#global logger
|
| 17 |
+
logger = GlobalSettings.logger
|
| 18 |
+
|
| 19 |
+
ssl._create_default_https_context = ssl._create_unverified_context
|
| 20 |
+
|
| 21 |
+
Entrez.email = "casper2informatics@gmail.com"
|
| 22 |
+
|
| 23 |
+
#model for filtering columns in ncbi table
|
| 24 |
+
class CustomProxyModel(QtCore.QSortFilterProxyModel):
|
| 25 |
+
def __init__(self, parent=None):
|
| 26 |
+
print("Initializing CustomProxyModel")
|
| 27 |
+
try:
|
| 28 |
+
super().__init__(parent)
|
| 29 |
+
self._filters = dict()
|
| 30 |
+
except Exception as e:
|
| 31 |
+
show_error("Error initializing CustomProxyModel class in ncbi tool.", e)
|
| 32 |
+
|
| 33 |
+
@property
|
| 34 |
+
def filters(self):
|
| 35 |
+
try:
|
| 36 |
+
return self._filters
|
| 37 |
+
except Exception as e:
|
| 38 |
+
show_error("Error in filter() in custom proxy model in ncbi tool.", e)
|
| 39 |
+
|
| 40 |
+
def setFilter(self, expresion, column):
|
| 41 |
+
try:
|
| 42 |
+
if expresion:
|
| 43 |
+
self.filters[column] = expresion
|
| 44 |
+
elif column in self.filters:
|
| 45 |
+
del self.filters[column]
|
| 46 |
+
self.invalidateFilter()
|
| 47 |
+
except Exception as e:
|
| 48 |
+
show_error("Error in setFilters() in custom proxy model in ncbi tool.", e)
|
| 49 |
+
|
| 50 |
+
def filterAcceptsRow(self, source_row, source_parent):
|
| 51 |
+
try:
|
| 52 |
+
for column, expresion in self.filters.items():
|
| 53 |
+
text = self.sourceModel().index(source_row, column, source_parent).data()
|
| 54 |
+
regex = QtCore.QRegExp(
|
| 55 |
+
expresion, QtCore.Qt.CaseInsensitive, QtCore.QRegExp.RegExp
|
| 56 |
+
)
|
| 57 |
+
if regex.indexIn(text) == -1:
|
| 58 |
+
return False
|
| 59 |
+
return True
|
| 60 |
+
|
| 61 |
+
except Exception as e:
|
| 62 |
+
show_error("Error in filterAcceptsRow() in custom proxy model in ncbi tool.", e)
|
| 63 |
+
|
| 64 |
+
#model for the data in the ncbi search table
|
| 65 |
+
class PandasModel(QtCore.QAbstractTableModel):
|
| 66 |
+
def __init__(self, df=pd.DataFrame(), parent=None):
|
| 67 |
+
try:
|
| 68 |
+
QtCore.QAbstractTableModel.__init__(self, parent=parent)
|
| 69 |
+
self._df = df.copy()
|
| 70 |
+
except Exception as e:
|
| 71 |
+
show_error("Error initializing PandasModel class in ncbi tool.", e)
|
| 72 |
+
|
| 73 |
+
def toDataFrame(self):
|
| 74 |
+
try:
|
| 75 |
+
return self._df.copy()
|
| 76 |
+
|
| 77 |
+
except Exception as e:
|
| 78 |
+
show_error("Error in toDataFrame() in Pandas Model in ncbi tool.", e)
|
| 79 |
+
|
| 80 |
+
def headerData(self, section, orientation, role=QtCore.Qt.DisplayRole):
|
| 81 |
+
try:
|
| 82 |
+
if role != QtCore.Qt.DisplayRole:
|
| 83 |
+
return QtCore.QVariant()
|
| 84 |
+
|
| 85 |
+
if orientation == QtCore.Qt.Horizontal:
|
| 86 |
+
try:
|
| 87 |
+
return self._df.columns.tolist()[section]
|
| 88 |
+
except (IndexError, ):
|
| 89 |
+
return QtCore.QVariant()
|
| 90 |
+
elif orientation == QtCore.Qt.Vertical:
|
| 91 |
+
try:
|
| 92 |
+
return self._df.index.tolist()[section]
|
| 93 |
+
except (IndexError, ):
|
| 94 |
+
return QtCore.QVariant()
|
| 95 |
+
except Exception as e:
|
| 96 |
+
show_error("Error in headerData() in Pandas Model in ncbi tool.", e)
|
| 97 |
+
|
| 98 |
+
def data(self, index, role=QtCore.Qt.DisplayRole):
|
| 99 |
+
try:
|
| 100 |
+
if role == QtCore.Qt.TextAlignmentRole:
|
| 101 |
+
return QtCore.Qt.AlignCenter
|
| 102 |
+
if role != QtCore.Qt.DisplayRole:
|
| 103 |
+
return QtCore.QVariant()
|
| 104 |
+
if not index.isValid():
|
| 105 |
+
return QtCore.QVariant()
|
| 106 |
+
|
| 107 |
+
return QtCore.QVariant(str(self._df.iloc[index.row(), index.column()]))
|
| 108 |
+
|
| 109 |
+
except Exception as e:
|
| 110 |
+
show_error("Error in data() in Pandas Model in ncbi tool.", e)
|
| 111 |
+
|
| 112 |
+
def setData(self, index, value, role):
|
| 113 |
+
try:
|
| 114 |
+
row = self._df.index[index.row()]
|
| 115 |
+
col = self._df.columns[index.column()]
|
| 116 |
+
if hasattr(value, 'toPyObject'):
|
| 117 |
+
# PyQt4 gets a QVariant
|
| 118 |
+
value = value.toPyObject()
|
| 119 |
+
else:
|
| 120 |
+
# PySide gets an unicode
|
| 121 |
+
dtype = self._df[col].dtype
|
| 122 |
+
if dtype != object:
|
| 123 |
+
value = None if value == '' else dtype.type(value)
|
| 124 |
+
self._df.set_value(row, col, value)
|
| 125 |
+
return True
|
| 126 |
+
except Exception as e:
|
| 127 |
+
show_error("Error in setData() in Pandas Model in ncbi tool.", e)
|
| 128 |
+
|
| 129 |
+
def rowCount(self, parent=QtCore.QModelIndex()):
|
| 130 |
+
try:
|
| 131 |
+
return len(self._df.index)
|
| 132 |
+
|
| 133 |
+
except Exception as e:
|
| 134 |
+
show_error("Error in rowCount() in Pandas Model in ncbi tool.", e)
|
| 135 |
+
|
| 136 |
+
def columnCount(self, parent=QtCore.QModelIndex()):
|
| 137 |
+
try:
|
| 138 |
+
return len(self._df.columns)
|
| 139 |
+
except Exception as e:
|
| 140 |
+
show_error("Error in columnCount() in Pandas Model in ncbi tool.", e)
|
| 141 |
+
|
| 142 |
+
def sort(self, column, order):
|
| 143 |
+
try:
|
| 144 |
+
colname = self._df.columns.tolist()[column]
|
| 145 |
+
self.layoutAboutToBeChanged.emit()
|
| 146 |
+
self._df.sort_values(colname, ascending=order, inplace=True)
|
| 147 |
+
self._df.reset_index(inplace=True, drop=True)
|
| 148 |
+
self.layoutChanged.emit()
|
| 149 |
+
except Exception as e:
|
| 150 |
+
show_error("Error in sort() in Pandas Model in ncbi tool.", e)
|
| 151 |
+
|
| 152 |
+
## Taken from StackOverflow: https://stackoverflow.com/questions/57607072/update-pyqt-progress-from-another-thread-running-ftp-download
|
| 153 |
+
class DownloadThread(QtCore.QThread):
|
| 154 |
+
""" Overall signals """
|
| 155 |
+
finished = QtCore.pyqtSignal(object)
|
| 156 |
+
started = QtCore.pyqtSignal(object)
|
| 157 |
+
|
| 158 |
+
""" Download specific signals """
|
| 159 |
+
data_progress = QtCore.pyqtSignal(object) # This signal emits progress data for the progress bar
|
| 160 |
+
data_size = QtCore.pyqtSignal(object) # This signal emits the size of the file being downloaded
|
| 161 |
+
file_started = QtCore.pyqtSignal(object) # This signal emits when the file starts downloading
|
| 162 |
+
file_finished = QtCore.pyqtSignal(object) # This signal emits the name of the file downloaded
|
| 163 |
+
|
| 164 |
+
def __init__(self,parent,url,id):
|
| 165 |
+
try:
|
| 166 |
+
QtCore.QThread.__init__(self,parent)
|
| 167 |
+
self.id = id
|
| 168 |
+
self.url = url # Initialize URL
|
| 169 |
+
self.ftp = FTP('ftp.ncbi.nlm.nih.gov') # Initialize FTP object
|
| 170 |
+
self.ftp.login()
|
| 171 |
+
except Exception as e:
|
| 172 |
+
show_error("Error initializing Thread class in ncbi tool.", e)
|
| 173 |
+
|
| 174 |
+
def run(self):
|
| 175 |
+
try:
|
| 176 |
+
### Start by making sure the url is valid
|
| 177 |
+
if self.url == "":
|
| 178 |
+
self.finished.emit((self.id, False))
|
| 179 |
+
return
|
| 180 |
+
else:
|
| 181 |
+
self.started.emit(self.id)
|
| 182 |
+
self.ftp.cwd(self.url) # Change to appropriate directory
|
| 183 |
+
dir_files = self.ftp.nlst() # Get list of files in directory
|
| 184 |
+
for file in dir_files: # Loop through every file in the directory
|
| 185 |
+
if GlobalSettings.mainWindow.ncbi.gbff_checkbox.isChecked(): # If a GBFF is supposed to be downloaded
|
| 186 |
+
if file.find('genomic.gbff') != -1: # If a GBFF exists in this directory
|
| 187 |
+
|
| 188 |
+
# check OS for output path
|
| 189 |
+
if platform.system() == "Windows":
|
| 190 |
+
output_file = GlobalSettings.CSPR_DB + "\\GBFF\\" + file
|
| 191 |
+
else:
|
| 192 |
+
output_file = GlobalSettings.CSPR_DB + "/GBFF/" + file
|
| 193 |
+
|
| 194 |
+
self.ftp.voidcmd('TYPE I')
|
| 195 |
+
totalsize = self.ftp.size(file) # Get size of file that is being downloaded
|
| 196 |
+
# The first signal sets the maximum for the progress bar
|
| 197 |
+
self.file_started.emit((self.id,'Downloading GBFF: ' + str(round(totalsize/1e6,2)) + 'MB...',str(totalsize))) # Emit that the file download is starting and size of file
|
| 198 |
+
with open(output_file, 'wb') as self.f:
|
| 199 |
+
self.ftp.retrbinary(f"RETR {file}", self.file_write) # Download the file, emitting progress as we go
|
| 200 |
+
self.decompress_file(output_file) # Decompress the file
|
| 201 |
+
self.file_finished.emit((self.id,'GBFF Downloaded!',output_file)) # Once download is finished, emit signal
|
| 202 |
+
|
| 203 |
+
if GlobalSettings.mainWindow.ncbi.fna_checkbox.isChecked(): # If a FNA is supposed to be downloaded
|
| 204 |
+
if file.find('genomic.fna') != -1 and file.find('_cds_') == -1 and file.find('_rna_') == -1: # If a FNA exists in this directory
|
| 205 |
+
|
| 206 |
+
# check OS for output path
|
| 207 |
+
if platform.system() == "Windows":
|
| 208 |
+
output_file = GlobalSettings.CSPR_DB + "\\FNA\\" + file
|
| 209 |
+
else:
|
| 210 |
+
output_file = GlobalSettings.CSPR_DB + "/FNA/" + file
|
| 211 |
+
|
| 212 |
+
self.ftp.voidcmd('TYPE I')
|
| 213 |
+
totalsize = self.ftp.size(file) # Get size of file that is being downloaded
|
| 214 |
+
self.file_started.emit((self.id,'Downloading FNA: ' + str(round(totalsize/1e6,2)) + 'MB...',str(totalsize))) # Emit that file download is starting
|
| 215 |
+
with open(output_file, 'wb') as self.f:
|
| 216 |
+
self.ftp.retrbinary(f"RETR {file}", self.file_write) # Download the file
|
| 217 |
+
|
| 218 |
+
self.decompress_file(output_file) # Decompress the file
|
| 219 |
+
self.file_finished.emit((self.id,'FNA Downloaded!',output_file)) # Once download is finished, emit signal
|
| 220 |
+
self.finished.emit((self.id,True))
|
| 221 |
+
self.ftp.quit() # Stop the FTP connection once everything has been downloaded
|
| 222 |
+
except Exception as e:
|
| 223 |
+
show_error("Error downloading file within DownloadThread class.", e)
|
| 224 |
+
|
| 225 |
+
def file_write(self, data):
|
| 226 |
+
self.f.write(data) # Write the downloaded data to a file
|
| 227 |
+
# The other signals increase a progress
|
| 228 |
+
self.data_progress.emit((self.id,str(len(data)))) # Emit a signal updating progress
|
| 229 |
+
|
| 230 |
+
def decompress_file(self, filename):
|
| 231 |
+
try:
|
| 232 |
+
block_size = 65536
|
| 233 |
+
with gzip.open(filename, 'rb') as f_in:
|
| 234 |
+
with open(str(filename).replace('.gz', ''), 'wb') as f_out:
|
| 235 |
+
while True:
|
| 236 |
+
block = f_in.read(block_size)
|
| 237 |
+
if not block:
|
| 238 |
+
break
|
| 239 |
+
else:
|
| 240 |
+
f_out.write(block)
|
| 241 |
+
os.remove(str(filename))
|
| 242 |
+
except Exception as e:
|
| 243 |
+
show_error("Error in decompress_file() in ncbi tool.", e)
|
| 244 |
+
|
| 245 |
+
class NCBI_search_tool(QtWidgets.QMainWindow):
|
| 246 |
+
def __init__(self):
|
| 247 |
+
try:
|
| 248 |
+
print("Initializing NCBI search tool...")
|
| 249 |
+
super(NCBI_search_tool, self).__init__()
|
| 250 |
+
uic.loadUi(GlobalSettings.appdir + 'ui/ncbi.ui', self)
|
| 251 |
+
self.setWindowIcon(Qt.QIcon(GlobalSettings.appdir + "cas9image.ico"))
|
| 252 |
+
self.setWindowTitle("NCBI Download Tool")
|
| 253 |
+
self.logicalIndex = 0
|
| 254 |
+
self.filters = dict()
|
| 255 |
+
self.download_button.clicked.connect(self.download_files_wrapper)
|
| 256 |
+
self.search_button.clicked.connect(self.query_db)
|
| 257 |
+
self.ncbi_table.verticalHeader().hide()
|
| 258 |
+
self.all_rows.clicked.connect(self.select_all)
|
| 259 |
+
self.back_button.clicked.connect(self.go_back)
|
| 260 |
+
self.ncbi_table.setFocusPolicy(QtCore.Qt.NoFocus)
|
| 261 |
+
self.progressBar.setValue(0)
|
| 262 |
+
self.rename_window = rename_window()
|
| 263 |
+
self.rename_window.submit_button.clicked.connect(self.submit_rename)
|
| 264 |
+
self.rename_window.go_back.clicked.connect(self.rename_go_back)
|
| 265 |
+
self.df = pd.DataFrame()
|
| 266 |
+
groupbox_style = """
|
| 267 |
+
QGroupBox:title{subcontrol-origin: margin;
|
| 268 |
+
left: 10px;
|
| 269 |
+
padding: 0 5px 0 5px;}
|
| 270 |
+
QGroupBox#Step1{border: 2px solid rgb(111,181,110);
|
| 271 |
+
border-radius: 9px;
|
| 272 |
+
font: bold 14pt 'Arial';
|
| 273 |
+
margin-top: 10px;}"""
|
| 274 |
+
self.Step1.setStyleSheet(groupbox_style)
|
| 275 |
+
self.Step2.setStyleSheet(groupbox_style.replace("Step1","Step2"))
|
| 276 |
+
self.Step3.setStyleSheet(groupbox_style.replace("Step1","Step3"))
|
| 277 |
+
self.ncbi_table.setSelectionMode(QtWidgets.QAbstractItemView.MultiSelection)
|
| 278 |
+
self.ncbi_table.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
|
| 279 |
+
#navigation page
|
| 280 |
+
self.goToPrompt = goToPrompt()
|
| 281 |
+
self.goToPrompt.stay.clicked.connect(self.stay)
|
| 282 |
+
self.goToPrompt.close.clicked.connect(self.close)
|
| 283 |
+
|
| 284 |
+
#loading label
|
| 285 |
+
self.loading_window = loading_window()
|
| 286 |
+
|
| 287 |
+
self.genbank_checkbox.toggled.connect(self.check_genbank)
|
| 288 |
+
|
| 289 |
+
self.first_show = True
|
| 290 |
+
scale_ui(self, custom_scale_width=1000, custom_scale_height=750)
|
| 291 |
+
self.fontSize = 12
|
| 292 |
+
except Exception as e:
|
| 293 |
+
show_error("Error initializing NCBI_search_tool class.", e)
|
| 294 |
+
|
| 295 |
+
def check_genbank(self):
|
| 296 |
+
if self.genbank_checkbox.isChecked():
|
| 297 |
+
show_message(
|
| 298 |
+
font_size=12,
|
| 299 |
+
title="Warning!",
|
| 300 |
+
message="The GenBank collection may contain poorly or partially annotated annotation files. We highly recommend using the RefSeq collection if it is available.",
|
| 301 |
+
icon=QtWidgets.QMessageBox.Icon.Warning
|
| 302 |
+
)
|
| 303 |
+
else:
|
| 304 |
+
pass
|
| 305 |
+
|
| 306 |
+
def go_back(self):
|
| 307 |
+
try:
|
| 308 |
+
""" Clear table """
|
| 309 |
+
self.df = pd.DataFrame() ###Make empty DF
|
| 310 |
+
self.model = PandasModel(self.df)
|
| 311 |
+
self.proxy = CustomProxyModel(self)
|
| 312 |
+
self.proxy.setSourceModel(self.model)
|
| 313 |
+
self.ncbi_table.setModel(self.proxy)
|
| 314 |
+
self.ncbi_table.verticalHeader().hide()
|
| 315 |
+
""" Clear all line edits """
|
| 316 |
+
self.organism_line_edit.clear()
|
| 317 |
+
self.infra_name_line_edit.clear()
|
| 318 |
+
self.ret_max_line_edit.setText("100")
|
| 319 |
+
self.infra_name_line_edit.clear()
|
| 320 |
+
""" Reset all checkboxes """
|
| 321 |
+
self.yes_box.setChecked(False)
|
| 322 |
+
self.genbank_checkbox.setChecked(False)
|
| 323 |
+
self.refseq_checkbox.setChecked(False)
|
| 324 |
+
self.gbff_checkbox.setChecked(False)
|
| 325 |
+
self.fna_checkbox.setChecked(False)
|
| 326 |
+
""" Hide window """
|
| 327 |
+
self.close()
|
| 328 |
+
except Exception as e:
|
| 329 |
+
show_error("Error in go_back() in ncbi tool.", e)
|
| 330 |
+
|
| 331 |
+
@QtCore.pyqtSlot()
|
| 332 |
+
def query_db(self):
|
| 333 |
+
try:
|
| 334 |
+
self.loading_window.loading_bar.setValue(5)
|
| 335 |
+
center_ui(self.loading_window)
|
| 336 |
+
self.loading_window.show()
|
| 337 |
+
QtCore.QCoreApplication.processEvents()
|
| 338 |
+
|
| 339 |
+
#setup table
|
| 340 |
+
self.comboBox = QtWidgets.QComboBox(self)
|
| 341 |
+
self.horizontalHeader = self.ncbi_table.horizontalHeader()
|
| 342 |
+
self.horizontalHeader.sectionClicked.connect(self.on_view_horizontalHeader_sectionClicked)
|
| 343 |
+
|
| 344 |
+
#Build Query commands
|
| 345 |
+
retmax = int(self.ret_max_line_edit.text())
|
| 346 |
+
if retmax == "":
|
| 347 |
+
retmax = 100
|
| 348 |
+
org = self.organism_line_edit.text()
|
| 349 |
+
term = '"' + org + '"[Organism]'
|
| 350 |
+
if self.yes_box.isChecked():
|
| 351 |
+
term += ' AND "Complete Genome"[Assembly Level]'
|
| 352 |
+
if self.infra_name_line_edit.text() != "":
|
| 353 |
+
term += ' AND "' + self.infra_name_line_edit.text() + '"[Infraspecific name]'
|
| 354 |
+
|
| 355 |
+
#Search DB for IDs
|
| 356 |
+
handle = Entrez.esearch(db="assembly", retmax=retmax, term=term)
|
| 357 |
+
content = handle.readlines()
|
| 358 |
+
content = "".join(str(content))
|
| 359 |
+
#bs_content = BeautifulSoup(content, "lxml")
|
| 360 |
+
bs_content = BeautifulSoup(content, "html.parser")
|
| 361 |
+
|
| 362 |
+
self.loading_window.loading_bar.setValue(20)
|
| 363 |
+
QtCore.QCoreApplication.processEvents()
|
| 364 |
+
|
| 365 |
+
#Extract IDs
|
| 366 |
+
idlist = bs_content.find('idlist')
|
| 367 |
+
ids = idlist.find_all('id')
|
| 368 |
+
ids = [i.text for i in ids]
|
| 369 |
+
|
| 370 |
+
self.loading_window.loading_bar.setValue(35)
|
| 371 |
+
QtCore.QCoreApplication.processEvents()
|
| 372 |
+
|
| 373 |
+
# Get Details on IDs
|
| 374 |
+
handle = Entrez.esummary(db="assembly", id=','.join(ids))
|
| 375 |
+
content = handle.readlines()
|
| 376 |
+
handle.close()
|
| 377 |
+
content = "".join(str(content))
|
| 378 |
+
#bs_content = BeautifulSoup(content, 'lxml')
|
| 379 |
+
bs_content = BeautifulSoup(content, "html.parser")
|
| 380 |
+
|
| 381 |
+
self.loading_window.loading_bar.setValue(55)
|
| 382 |
+
|
| 383 |
+
QtCore.QCoreApplication.processEvents()
|
| 384 |
+
|
| 385 |
+
#Prep Data for Table
|
| 386 |
+
assembly_name = bs_content.find_all('assemblyname')
|
| 387 |
+
genbank_ids = bs_content.find_all('genbank')
|
| 388 |
+
refseq_ids = bs_content.find_all('refseq')
|
| 389 |
+
assembly_status = bs_content.find_all('assemblystatus')
|
| 390 |
+
species_name = bs_content.find_all('speciesname')
|
| 391 |
+
temp_strains = bs_content.find_all('infraspecieslist')
|
| 392 |
+
assembly_name = [i.text for i in assembly_name]
|
| 393 |
+
genbank_ids = [i.text for i in genbank_ids]
|
| 394 |
+
refseq_ids = [i.text for i in refseq_ids]
|
| 395 |
+
assembly_status = [i.text for i in assembly_status]
|
| 396 |
+
species_name = [i.text for i in species_name]
|
| 397 |
+
ids = [int(i) for i in ids]
|
| 398 |
+
strains = []
|
| 399 |
+
for i in range(len(genbank_ids)):
|
| 400 |
+
temp_str = str(temp_strains[i])
|
| 401 |
+
#temp_str = BeautifulSoup(temp_str, 'lxml')
|
| 402 |
+
temp_str = BeautifulSoup(temp_str, 'html.parser')
|
| 403 |
+
temp_str = temp_str.find('sub_value')
|
| 404 |
+
if temp_str != None:
|
| 405 |
+
strains.append(temp_str.text)
|
| 406 |
+
else:
|
| 407 |
+
strains.append('N/A')
|
| 408 |
+
|
| 409 |
+
self.loading_window.loading_bar.setValue(65)
|
| 410 |
+
QtCore.QCoreApplication.processEvents()
|
| 411 |
+
|
| 412 |
+
#Get ftp links
|
| 413 |
+
genbank_links = bs_content.find_all('ftppath_genbank')
|
| 414 |
+
refseq_links = bs_content.find_all('ftppath_refseq')
|
| 415 |
+
refseq_links = bs_content.find_all('ftppath_refseq')
|
| 416 |
+
genbank_links = [i.text for i in genbank_links]
|
| 417 |
+
refseq_links = [i.text for i in refseq_links]
|
| 418 |
+
self.genbank_ftp_dict = {}
|
| 419 |
+
self.refseq_ftp_dict = {}
|
| 420 |
+
for i in range(len(ids)):
|
| 421 |
+
if genbank_ids[i] == '':
|
| 422 |
+
self.genbank_ftp_dict[ids[i]] = ''
|
| 423 |
+
else:
|
| 424 |
+
self.genbank_ftp_dict[ids[i]] = genbank_links[i] + '/'
|
| 425 |
+
if refseq_ids[i] == '':
|
| 426 |
+
self.refseq_ftp_dict[ids[i]] = ''
|
| 427 |
+
else:
|
| 428 |
+
self.refseq_ftp_dict[ids[i]] = refseq_links[i] + '/'
|
| 429 |
+
|
| 430 |
+
self.loading_window.loading_bar.setValue(80)
|
| 431 |
+
QtCore.QCoreApplication.processEvents()
|
| 432 |
+
|
| 433 |
+
#Build dataframe
|
| 434 |
+
self.df = pd.DataFrame({'ID': ids,
|
| 435 |
+
'Species Name' : species_name,
|
| 436 |
+
'Strain' : strains,
|
| 437 |
+
'Assembly Name' : assembly_name,
|
| 438 |
+
'GenBank assembly accession': genbank_ids,
|
| 439 |
+
'RefSeq assembly accession': refseq_ids,
|
| 440 |
+
'Assembly Status': assembly_status})
|
| 441 |
+
|
| 442 |
+
self.loading_window.loading_bar.setValue(90)
|
| 443 |
+
QtCore.QCoreApplication.processEvents()
|
| 444 |
+
|
| 445 |
+
#Build table view
|
| 446 |
+
self.df.replace('', 'N/A', inplace=True)
|
| 447 |
+
self.model = PandasModel(self.df)
|
| 448 |
+
self.proxy = CustomProxyModel(self)
|
| 449 |
+
self.proxy.setSourceModel(self.model)
|
| 450 |
+
self.ncbi_table.setModel(self.proxy)
|
| 451 |
+
self.ncbi_table.resizeColumnsToContents()
|
| 452 |
+
self.comboBox.addItems(["{0}".format(col) for col in self.model._df.columns])
|
| 453 |
+
self.activateWindow()
|
| 454 |
+
|
| 455 |
+
#close loading gif
|
| 456 |
+
self.loading_window.hide()
|
| 457 |
+
self.loading_window.loading_bar.setValue(0)
|
| 458 |
+
QtCore.QCoreApplication.processEvents()
|
| 459 |
+
except Exception as e:
|
| 460 |
+
show_error("Error in query_db() in ncbi tool.", e)
|
| 461 |
+
|
| 462 |
+
@QtCore.pyqtSlot(int)
|
| 463 |
+
def on_view_horizontalHeader_sectionClicked(self, logicalIndex):
|
| 464 |
+
try:
|
| 465 |
+
self.logicalIndex = logicalIndex
|
| 466 |
+
self.menuValues = QtWidgets.QMenu(self)
|
| 467 |
+
self.signalMapper = QtCore.QSignalMapper(self)
|
| 468 |
+
self.comboBox.blockSignals(True)
|
| 469 |
+
self.comboBox.setCurrentIndex(logicalIndex)
|
| 470 |
+
self.comboBox.blockSignals(True)
|
| 471 |
+
valuesUnique = self.model._df.iloc[:, logicalIndex].unique()
|
| 472 |
+
if logicalIndex == 0:
|
| 473 |
+
valuesUnique = ['Sort: 0-9', 'Sort: 9-0']
|
| 474 |
+
elif logicalIndex == 2:
|
| 475 |
+
valuesUnique = ['Exclude N/A', 'Only N/A', 'Sort: A-Z', 'Sort: Z-A']
|
| 476 |
+
elif logicalIndex == 3:
|
| 477 |
+
valuesUnique = ['Sort: A-Z', 'Sort: Z-A']
|
| 478 |
+
elif logicalIndex == 4 or logicalIndex == 5:
|
| 479 |
+
valuesUnique = ['Exclude N/A', 'Only N/A', 'Sort: A-Z', 'Sort: Z-A']
|
| 480 |
+
|
| 481 |
+
actionAll = QtWidgets.QAction("All", self)
|
| 482 |
+
actionAll.triggered.connect(self.on_actionAll_triggered)
|
| 483 |
+
self.menuValues.addAction(actionAll)
|
| 484 |
+
self.menuValues.addSeparator()
|
| 485 |
+
for actionNumber, actionName in enumerate(sorted(list(set(valuesUnique)))):
|
| 486 |
+
action = QtWidgets.QAction(actionName, self)
|
| 487 |
+
self.signalMapper.setMapping(action, actionNumber)
|
| 488 |
+
action.triggered.connect(self.signalMapper.map)
|
| 489 |
+
self.menuValues.addAction(action)
|
| 490 |
+
self.signalMapper.mapped.connect(self.on_signalMapper_mapped)
|
| 491 |
+
headerPos = self.ncbi_table.mapToGlobal(self.horizontalHeader.pos())
|
| 492 |
+
posY = headerPos.y() + self.horizontalHeader.height()
|
| 493 |
+
posX = headerPos.x() + self.horizontalHeader.sectionViewportPosition(logicalIndex)
|
| 494 |
+
|
| 495 |
+
self.menuValues.exec_(QtCore.QPoint(posX, posY))
|
| 496 |
+
except Exception as e:
|
| 497 |
+
show_error("Error in on_view_horizontalHeader_sectionClicked() in ncbi tool.", e)
|
| 498 |
+
|
| 499 |
+
@QtCore.pyqtSlot()
|
| 500 |
+
def on_actionAll_triggered(self):
|
| 501 |
+
try:
|
| 502 |
+
filterColumn = self.logicalIndex
|
| 503 |
+
self.proxy.setFilter("", filterColumn)
|
| 504 |
+
except Exception as e:
|
| 505 |
+
show_error("Error in on_actionAll_triggered() in ncbi tool.", e)
|
| 506 |
+
|
| 507 |
+
@QtCore.pyqtSlot(int)
|
| 508 |
+
def on_signalMapper_mapped(self, i):
|
| 509 |
+
try:
|
| 510 |
+
indices = self.ncbi_table.selectionModel().selectedRows()
|
| 511 |
+
#stringAction = self.signalMapper.mapping(i).text()
|
| 512 |
+
if self.logicalIndex == 0:
|
| 513 |
+
if i == 0:
|
| 514 |
+
self.model.sort(self.logicalIndex, QtCore.Qt.DescendingOrder)
|
| 515 |
+
else:
|
| 516 |
+
self.model.sort(self.logicalIndex, QtCore.Qt.AscendingOrder)
|
| 517 |
+
elif self.logicalIndex == 3:
|
| 518 |
+
if i == 0:
|
| 519 |
+
self.model.sort(self.logicalIndex, QtCore.Qt.DescendingOrder)
|
| 520 |
+
else:
|
| 521 |
+
self.model.sort(self.logicalIndex, QtCore.Qt.AscendingOrder)
|
| 522 |
+
elif self.logicalIndex == 2 or self.logicalIndex == 4 or self.logicalIndex == 5:
|
| 523 |
+
if i == 0:
|
| 524 |
+
stringAction = "(?!^N/A$)(^.*$)"
|
| 525 |
+
filterColumn = self.logicalIndex
|
| 526 |
+
self.proxy.setFilter(stringAction, filterColumn)
|
| 527 |
+
elif i == 1:
|
| 528 |
+
stringAction = "N/A"
|
| 529 |
+
filterColumn = self.logicalIndex
|
| 530 |
+
self.proxy.setFilter(stringAction, filterColumn)
|
| 531 |
+
elif i == 2:
|
| 532 |
+
self.model.sort(self.logicalIndex, QtCore.Qt.DescendingOrder)
|
| 533 |
+
else:
|
| 534 |
+
self.model.sort(self.logicalIndex, QtCore.Qt.AscendingOrder)
|
| 535 |
+
elif self.logicalIndex == 6:
|
| 536 |
+
stringAction = self.signalMapper.mapping(i).text()
|
| 537 |
+
filterColumn = self.logicalIndex
|
| 538 |
+
self.proxy.setFilter(stringAction, filterColumn)
|
| 539 |
+
except Exception as e:
|
| 540 |
+
show_error("Error in on_signalMapper_mapped() in ncbi tool.", e)
|
| 541 |
+
|
| 542 |
+
@QtCore.pyqtSlot()
|
| 543 |
+
def download_files_wrapper(self):
|
| 544 |
+
try:
|
| 545 |
+
self.progressBar.setValue(0)
|
| 546 |
+
|
| 547 |
+
#make sure rows are present in table
|
| 548 |
+
if self.df.shape[0] == 0:
|
| 549 |
+
show_message(
|
| 550 |
+
fontSize=self.fontSize,
|
| 551 |
+
icon=QtWidgets.QMessageBox.Icon.Critical,
|
| 552 |
+
title="No Query Results",
|
| 553 |
+
message="Please run an NCBI query to fill the table with results to choose from!"
|
| 554 |
+
)
|
| 555 |
+
return
|
| 556 |
+
|
| 557 |
+
#make sure user has selected at least one row
|
| 558 |
+
indices = self.ncbi_table.selectionModel().selectedRows()
|
| 559 |
+
if len(indices) == 0:
|
| 560 |
+
show_message(
|
| 561 |
+
fontSize=self.fontSize,
|
| 562 |
+
icon=QtWidgets.QMessageBox.Icon.Critical,
|
| 563 |
+
title="No Rows Selected",
|
| 564 |
+
message="Please select rows from the table!"
|
| 565 |
+
)
|
| 566 |
+
return
|
| 567 |
+
|
| 568 |
+
threadCount = QtCore.QThreadPool.globalInstance().maxThreadCount() # Get thread count
|
| 569 |
+
if len(indices) > threadCount:
|
| 570 |
+
show_message(
|
| 571 |
+
fontSize=self.fontSize,
|
| 572 |
+
icon=QtWidgets.QMessageBox.Icon.Critical,
|
| 573 |
+
title="Too Many Selections!",
|
| 574 |
+
message="You only have " + str(threadCount) + " threads avaiable to download with.\n\nPlease select " + str(threadCount) + " or fewer rows."
|
| 575 |
+
)
|
| 576 |
+
return
|
| 577 |
+
|
| 578 |
+
#make sure file type is selected
|
| 579 |
+
if self.gbff_checkbox.isChecked() == False and self.fna_checkbox.isChecked() == False:
|
| 580 |
+
show_message(
|
| 581 |
+
fontSize=self.fontSize,
|
| 582 |
+
icon=QtWidgets.QMessageBox.Icon.Critical,
|
| 583 |
+
title="No File Type Selected",
|
| 584 |
+
message="No file type selected. Please select the file types you want to download!"
|
| 585 |
+
)
|
| 586 |
+
return
|
| 587 |
+
self.download_files()
|
| 588 |
+
except Exception as e:
|
| 589 |
+
show_error("Error in download_files_wrapper() in ncbi tool.", e)
|
| 590 |
+
|
| 591 |
+
### When a new thread is started, spawn a label and progress bar for that thread and add it to the form layout.
|
| 592 |
+
def on_thread_start(self, data):
|
| 593 |
+
id = data # This is the id for the thread
|
| 594 |
+
tmp_lbl = QtWidgets.QLabel()
|
| 595 |
+
tmp_lbl.setText("Download(s) Started...")
|
| 596 |
+
tmp_bar = QtWidgets.QProgressBar()
|
| 597 |
+
self.labels[id] = tmp_lbl # Append thread label to list
|
| 598 |
+
self.progressbars[id] = tmp_bar # Append thread label to list
|
| 599 |
+
self.formLayout.addRow(tmp_lbl,tmp_bar) # Add label and bar to form layout
|
| 600 |
+
|
| 601 |
+
### When a thread is finished, update its label and progressbar for the last time
|
| 602 |
+
def on_thread_finish(self,data):
|
| 603 |
+
id = data[0]
|
| 604 |
+
my_bool = data[1]
|
| 605 |
+
if my_bool: # If thread finished succesfully
|
| 606 |
+
self.progressbars[id].setValue(int(self.progressbars[id].maximum())) #Make sure progress bar is full
|
| 607 |
+
self.labels[id].setText("Download(s) Complete!") #Make sure progress bar is full
|
| 608 |
+
self.progressBar.setValue(int(self.progressBar.value()+1)) # Increment overall progress bar when a thread finishes
|
| 609 |
+
QtWidgets.QApplication.processEvents() # Allow the progress bar to update
|
| 610 |
+
else:
|
| 611 |
+
self.progressBar.setMaximum(int(self.progressBar.maximum()-1)) # Subtract 1 from progress bar to reflect failed thread.
|
| 612 |
+
show_message(
|
| 613 |
+
fontSize=self.fontSize,
|
| 614 |
+
icon=QtWidgets.QMessageBox.Icon.Critical,
|
| 615 |
+
title="Link Failed!",
|
| 616 |
+
message="Failed to find a valid link for ID: " + str(id) + ". Please make sure this ID is available in the selected database."
|
| 617 |
+
)
|
| 618 |
+
return
|
| 619 |
+
|
| 620 |
+
### When a file download starts, update the label and progress bar
|
| 621 |
+
def on_file_start(self, data):
|
| 622 |
+
id = data[0] # This is the id for the thread
|
| 623 |
+
prompt = data[1] # This is the prompt to set the label to
|
| 624 |
+
maxval = int(data[2]) # This is the file size
|
| 625 |
+
self.progressbars[id].setValue(0) # Set max value of progressbar
|
| 626 |
+
self.progressbars[id].setMaximum(int(maxval/1e3)) # Set max value of progressbar
|
| 627 |
+
|
| 628 |
+
self.labels[id].setText(str(prompt)) # Set label text
|
| 629 |
+
|
| 630 |
+
## Taken from StackOverflow: https://stackoverflow.com/questions/57607072/update-pyqt-progress-from-another-thread-running-ftp-download
|
| 631 |
+
def on_progress_ready(self, data):
|
| 632 |
+
id = data[0] # This is the id for the thread
|
| 633 |
+
val = int(data[1]) # This is the increment
|
| 634 |
+
self.progressbars[id].setValue(int(self.progressbars[id].value() + val/1e3)) # Increment progress bar
|
| 635 |
+
|
| 636 |
+
### When a file download finishes, update the label and progress bar and add file name to list
|
| 637 |
+
def on_file_finish(self,data):
|
| 638 |
+
id = data[0] # This is the id for the thread
|
| 639 |
+
prompt = data[1] # This is the prompt to set the label to
|
| 640 |
+
file_name = data[2] # This is the filename
|
| 641 |
+
self.progressbars[id].setValue(int(self.progressbars[id].maximum())) # Make sure progress bar is set to max after finishing download
|
| 642 |
+
self.labels[id].setText(str(prompt))
|
| 643 |
+
self.files.append(str(file_name)) # Add filename to list of downloaded files
|
| 644 |
+
|
| 645 |
+
def clean_bars(self):
|
| 646 |
+
for key in self.progressbars:
|
| 647 |
+
label = self.formLayout.labelForField(self.progressbars[key])
|
| 648 |
+
if label is not None:
|
| 649 |
+
label.deleteLater()
|
| 650 |
+
self.progressbars[key].deleteLater()
|
| 651 |
+
|
| 652 |
+
self.labels.clear()
|
| 653 |
+
self.progressbars.clear()
|
| 654 |
+
self.threads.clear()
|
| 655 |
+
def clear_layout(self):
|
| 656 |
+
for i in reversed(range(self.formLayout.count())):
|
| 657 |
+
self.formLayout.itemAt(i).widget().deleteLater()
|
| 658 |
+
|
| 659 |
+
## Taken from StackOverflow: https://stackoverflow.com/questions/57607072/update-pyqt-progress-from-another-thread-running-ftp-download
|
| 660 |
+
def download_files(self):
|
| 661 |
+
try:
|
| 662 |
+
self.labels = {} # Key is the ID, value is the QLabel
|
| 663 |
+
self.progressbars = {} # Key is the ID, value is the QProgressBar
|
| 664 |
+
self.threads = {} # Key is the ID, value is the QThread
|
| 665 |
+
indices = self.ncbi_table.selectionModel().selectedRows()
|
| 666 |
+
len_ind = len(indices) # Get number of rows
|
| 667 |
+
self.progressBar.setMaximum(int(len_ind)) # Set overall progress bar to be equal to number of rows being downloaded
|
| 668 |
+
if len_ind == 0:
|
| 669 |
+
return
|
| 670 |
+
if self.genbank_checkbox.isChecked() == False and self.refseq_checkbox.isChecked() == False:
|
| 671 |
+
return
|
| 672 |
+
self.progressLabel.setText("Download(s) Started...") # Update progresslabel
|
| 673 |
+
self.files = [] # Initialize list to hold downloaded files
|
| 674 |
+
for index in indices: # For selected row(s) in table
|
| 675 |
+
NewIndex = self.ncbi_table.model().index(index.row(), 0) # Get index of selected row
|
| 676 |
+
id = self.ncbi_table.model().data(NewIndex) # Get ID from selected row
|
| 677 |
+
dirs = [] # Initialize list to hold links to ftp directories
|
| 678 |
+
if self.genbank_checkbox.isChecked():
|
| 679 |
+
genbank_ftp = self.genbank_ftp_dict[int(id)]
|
| 680 |
+
dirs.append(genbank_ftp)
|
| 681 |
+
else:
|
| 682 |
+
refseq_ftp = self.refseq_ftp_dict[int(id)]
|
| 683 |
+
dirs.append(refseq_ftp)
|
| 684 |
+
for dir in dirs: # Loop through the ftp links
|
| 685 |
+
url = str(dir).replace('ftp://ftp.ncbi.nlm.nih.gov', '') # Create new link
|
| 686 |
+
downloader = DownloadThread(parent=self,url=url,id=id) # Create a thread for the download
|
| 687 |
+
downloader.started.connect(self.on_thread_start) # Connect signal to function
|
| 688 |
+
downloader.finished.connect(self.on_thread_finish) # Connect signal to function
|
| 689 |
+
downloader.file_started.connect(self.on_file_start)
|
| 690 |
+
downloader.file_finished.connect(self.on_file_finish)
|
| 691 |
+
downloader.data_progress.connect(self.on_progress_ready) # Connect signal to function
|
| 692 |
+
self.threads[url] = downloader # Add thread to dictionary using the url as a key
|
| 693 |
+
downloader.start()
|
| 694 |
+
""" Make sure all threads are done before checking to see if files were downloaded """
|
| 695 |
+
while len([self.threads[t] for t in self.threads if self.threads[t].isRunning()]) > 0:
|
| 696 |
+
time.sleep(0.1)
|
| 697 |
+
QtWidgets.QApplication.processEvents()
|
| 698 |
+
self.progressBar.setValue(int(self.progressBar.maximum())) # Set progressBar to maximum
|
| 699 |
+
self.progressLabel.setText("Download(s) Complete!") # Set progressBar to maximum
|
| 700 |
+
|
| 701 |
+
self.clean_bars() # Clear out all the bars now that downloading is done
|
| 702 |
+
|
| 703 |
+
for i in range(len(self.files)):
|
| 704 |
+
self.files[i] = self.files[i].replace('.gz', '')
|
| 705 |
+
if platform.system() == 'Windows':
|
| 706 |
+
self.files[i] = self.files[i][self.files[i].rfind("\\")+1:]
|
| 707 |
+
else:
|
| 708 |
+
self.files[i] = self.files[i][self.files[i].rfind("/") + 1:]
|
| 709 |
+
|
| 710 |
+
if len(self.files) > 0:
|
| 711 |
+
self.rename_files(self.files)
|
| 712 |
+
else:
|
| 713 |
+
self.clear_layout()
|
| 714 |
+
self.clean_bars() # Clear out all the bars since the download failed
|
| 715 |
+
show_message(
|
| 716 |
+
fontSize = self.fontSize,
|
| 717 |
+
icon = QtWidgets.QMessageBox.Icon.Critical,
|
| 718 |
+
title = "No Files Downloaded",
|
| 719 |
+
message = "No files were downloaded from the selected NCBI files. Please make sure the selected files are available in the database selected."
|
| 720 |
+
)
|
| 721 |
+
return
|
| 722 |
+
|
| 723 |
+
except Exception as e:
|
| 724 |
+
show_error("Error in download_files() in ncbi tool.", e)
|
| 725 |
+
|
| 726 |
+
@QtCore.pyqtSlot()
|
| 727 |
+
def select_all(self):
|
| 728 |
+
try:
|
| 729 |
+
if self.all_rows.isChecked():
|
| 730 |
+
self.ncbi_table.selectAll()
|
| 731 |
+
else:
|
| 732 |
+
self.ncbi_table.clearSelection()
|
| 733 |
+
except Exception as e:
|
| 734 |
+
show_error("Error in select_all() in ncbi tool.", e)
|
| 735 |
+
|
| 736 |
+
def rename_files(self, files):
|
| 737 |
+
try:
|
| 738 |
+
msgBox = QtWidgets.QMessageBox()
|
| 739 |
+
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 740 |
+
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Question)
|
| 741 |
+
msgBox.setWindowTitle("Rename Files")
|
| 742 |
+
msgBox.setText("Would you like to rename the downloaded files?")
|
| 743 |
+
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Yes)
|
| 744 |
+
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.No)
|
| 745 |
+
msgBox.exec()
|
| 746 |
+
|
| 747 |
+
if msgBox.result() == QtWidgets.QMessageBox.Yes:
|
| 748 |
+
self.rename_window.rename_table.setRowCount(len(files))
|
| 749 |
+
cnt = 0
|
| 750 |
+
for file in files:
|
| 751 |
+
item = QtWidgets.QTableWidgetItem(file)
|
| 752 |
+
item.setFlags(QtCore.Qt.ItemIsEnabled)
|
| 753 |
+
self.rename_window.rename_table.setItem(cnt, 0, item)
|
| 754 |
+
|
| 755 |
+
self.rename_window.rename_table.setCellWidget(cnt, 1, QtWidgets.QLineEdit())
|
| 756 |
+
cnt += 1
|
| 757 |
+
|
| 758 |
+
header = self.rename_window.rename_table.horizontalHeader()
|
| 759 |
+
self.rename_window.rename_table.resizeColumnsToContents()
|
| 760 |
+
header.setSectionResizeMode(0, QtWidgets.QHeaderView.ResizeToContents)
|
| 761 |
+
header.setSectionResizeMode(1, QtWidgets.QHeaderView.Stretch)
|
| 762 |
+
center_ui(self.rename_window)
|
| 763 |
+
self.rename_window.show()
|
| 764 |
+
self.rename_window.activateWindow()
|
| 765 |
+
else:
|
| 766 |
+
GlobalSettings.mainWindow.fill_annotation_dropdown()
|
| 767 |
+
self.goToPrompt.show()
|
| 768 |
+
self.goToPrompt.activateWindow()
|
| 769 |
+
except Exception as e:
|
| 770 |
+
show_error("Error in rename_files() in ncbi tool.", e)
|
| 771 |
+
|
| 772 |
+
def rename_go_back(self):
|
| 773 |
+
try:
|
| 774 |
+
self.rename_window.close()
|
| 775 |
+
except Exception as e:
|
| 776 |
+
show_error("Error in rename_go_back() in ncbi tool.", e)
|
| 777 |
+
|
| 778 |
+
def submit_rename(self):
|
| 779 |
+
try:
|
| 780 |
+
#loop through columns and rename the files
|
| 781 |
+
for row in range(self.rename_window.rename_table.rowCount()):
|
| 782 |
+
orig = str(self.rename_window.rename_table.item(row, 0).text())
|
| 783 |
+
new = str(self.rename_window.rename_table.cellWidget(row, 1).text())
|
| 784 |
+
if new != "":
|
| 785 |
+
if orig.find(".gbff")!= -1:
|
| 786 |
+
if new.find(".") != -1:
|
| 787 |
+
new = new[:new.find(".")]
|
| 788 |
+
new = new + ".gbff"
|
| 789 |
+
elif orig.find(".fna") != -1:
|
| 790 |
+
if new.find(".") != -1:
|
| 791 |
+
new = new[:new.find(".")]
|
| 792 |
+
new = new + ".fna"
|
| 793 |
+
|
| 794 |
+
if platform.system() == "Windows":
|
| 795 |
+
if new.find(".gbff") != -1:
|
| 796 |
+
if os.path.isfile(GlobalSettings.CSPR_DB + "\\GBFF\\" + new) == False:
|
| 797 |
+
os.rename(GlobalSettings.CSPR_DB + "\\GBFF\\" + orig, GlobalSettings.CSPR_DB + "\\GBFF\\" + new)
|
| 798 |
+
else:
|
| 799 |
+
show_message(
|
| 800 |
+
fontSize = self.fontSize,
|
| 801 |
+
icon = QtWidgets.QMessageBox.Icon.Critical,
|
| 802 |
+
title = "Renaming Error",
|
| 803 |
+
message = "The filename: " + str(new) + " already exists. Please use a different name."
|
| 804 |
+
)
|
| 805 |
+
return
|
| 806 |
+
else:
|
| 807 |
+
if os.path.isfile(GlobalSettings.CSPR_DB + "\\FNA\\" + new) == False:
|
| 808 |
+
os.rename(GlobalSettings.CSPR_DB + "\\FNA\\" + orig, GlobalSettings.CSPR_DB + "\\FNA\\" + new)
|
| 809 |
+
else:
|
| 810 |
+
show_message(
|
| 811 |
+
fontSize = self.fontSize,
|
| 812 |
+
icon = QtWidgets.QMessageBox.Icon.Critical,
|
| 813 |
+
title = "Renaming Error",
|
| 814 |
+
message = "The filename: " + str(new) + " already exists. Please use a different name."
|
| 815 |
+
)
|
| 816 |
+
return
|
| 817 |
+
else:
|
| 818 |
+
#unix cannot have spaces in paths
|
| 819 |
+
new = new.replace(" ","")
|
| 820 |
+
if new.find(".gbff") != -1:
|
| 821 |
+
if os.path.isfile(GlobalSettings.CSPR_DB + "/GBFF/" + new) == False:
|
| 822 |
+
os.rename(GlobalSettings.CSPR_DB + "/GBFF/" + orig, GlobalSettings.CSPR_DB + "/GBFF/" + new)
|
| 823 |
+
else:
|
| 824 |
+
show_message(
|
| 825 |
+
fontSize = self.fontSize,
|
| 826 |
+
icon = QtWidgets.QMessageBox.Icon.Critical,
|
| 827 |
+
title = "Renaming Error",
|
| 828 |
+
message = "The filename: " + str(new) + " already exists. Please use a different name."
|
| 829 |
+
)
|
| 830 |
+
return
|
| 831 |
+
else:
|
| 832 |
+
if os.path.isfile(GlobalSettings.CSPR_DB + "/FNA/" + new) == False:
|
| 833 |
+
os.rename(GlobalSettings.CSPR_DB + "/FNA/" + orig, GlobalSettings.CSPR_DB + "/FNA/" + new)
|
| 834 |
+
else:
|
| 835 |
+
show_message(
|
| 836 |
+
fontSize = self.fontSize,
|
| 837 |
+
icon = QtWidgets.QMessageBox.Icon.Critical,
|
| 838 |
+
title = "Renaming Error",
|
| 839 |
+
message = "The filename: " + str(new) + " already exists. Please use a different name."
|
| 840 |
+
)
|
| 841 |
+
return
|
| 842 |
+
|
| 843 |
+
self.rename_window.rename_table.setRowCount(0)
|
| 844 |
+
self.rename_window.close()
|
| 845 |
+
GlobalSettings.mainWindow.fill_annotation_dropdown()
|
| 846 |
+
center_ui(self.goToPrompt)
|
| 847 |
+
self.goToPrompt.show()
|
| 848 |
+
self.goToPrompt.activateWindow()
|
| 849 |
+
except Exception as e:
|
| 850 |
+
show_error("Error in submit_rename() in ncbi tool.", e)
|
| 851 |
+
|
| 852 |
+
def stay(self):
|
| 853 |
+
try:
|
| 854 |
+
self.goToPrompt.hide()
|
| 855 |
+
except Exception as e:
|
| 856 |
+
show_error("Error in stay() in ncbi tool.", e)
|
| 857 |
+
|
| 858 |
+
def close(self):
|
| 859 |
+
try:
|
| 860 |
+
self.hide()
|
| 861 |
+
self.goToPrompt.hide()
|
| 862 |
+
except Exception as e:
|
| 863 |
+
show_error("Error in close() in ncbi tool.", e)
|
| 864 |
+
|
| 865 |
+
class goToPrompt(QtWidgets.QMainWindow):
|
| 866 |
+
def __init__(self):
|
| 867 |
+
try:
|
| 868 |
+
super(goToPrompt, self).__init__()
|
| 869 |
+
uic.loadUi(GlobalSettings.appdir + 'ui/ncbi_nav_page.ui', self)
|
| 870 |
+
self.setWindowTitle("Navigate")
|
| 871 |
+
self.setWindowIcon(Qt.QIcon(GlobalSettings.appdir + "cas9image.ico"))
|
| 872 |
+
self.label.setText("Successfully downloaded file(s) to the CASPERdb directory:\n" + GlobalSettings.CSPR_DB)
|
| 873 |
+
self.label.setAlignment(QtCore.Qt.AlignCenter)
|
| 874 |
+
groupbox_style = """
|
| 875 |
+
QGroupBox:title{subcontrol-origin: margin;
|
| 876 |
+
left: 10px;
|
| 877 |
+
padding: 0 5px 0 5px;}
|
| 878 |
+
QGroupBox#groupBox{border: 2px solid rgb(111,181,110);
|
| 879 |
+
border-radius: 9px;
|
| 880 |
+
font: bold 14pt 'Arial';
|
| 881 |
+
margin-top: 10px;}"""
|
| 882 |
+
self.groupBox.setStyleSheet(groupbox_style)
|
| 883 |
+
|
| 884 |
+
# self.scaleUI()
|
| 885 |
+
scale_ui(self, custom_scale_width=575, custom_scale_height=225)
|
| 886 |
+
except Exception as e:
|
| 887 |
+
show_error("Error initializing goToPrompt class in ncbi tool.", e)
|
| 888 |
+
|
| 889 |
+
class rename_window(QtWidgets.QMainWindow):
|
| 890 |
+
def __init__(self):
|
| 891 |
+
try:
|
| 892 |
+
super(rename_window, self).__init__()
|
| 893 |
+
uic.loadUi(GlobalSettings.appdir + "ui/ncbi_rename_window.ui", self)
|
| 894 |
+
self.setWindowIcon(Qt.QIcon(GlobalSettings.appdir + "cas9image.ico"))
|
| 895 |
+
self.setWindowTitle("Rename Files")
|
| 896 |
+
self.rename_table.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.AdjustToContents)
|
| 897 |
+
self.rename_table.setColumnCount(2)
|
| 898 |
+
self.rename_table.setHorizontalHeaderLabels(['Original Filename', 'New Filename'])
|
| 899 |
+
|
| 900 |
+
scale_ui(self, custom_scale_width=575, custom_scale_height=300)
|
| 901 |
+
except Exception as e:
|
| 902 |
+
show_error("Error initializing rename_window class in ncbi tool.", e)
|
| 903 |
+
|
| 904 |
+
#loading window UI class for when data is loading
|
| 905 |
+
class loading_window(QtWidgets.QMainWindow):
|
| 906 |
+
def __init__(self):
|
| 907 |
+
try:
|
| 908 |
+
super(loading_window, self).__init__()
|
| 909 |
+
uic.loadUi(GlobalSettings.appdir + "ui/loading_data_form.ui", self)
|
| 910 |
+
self.loading_bar.setValue(0)
|
| 911 |
+
self.setWindowTitle("Loading NCBI Data")
|
| 912 |
+
self.setWindowIcon(Qt.QIcon(GlobalSettings.appdir + "cas9image.ico"))
|
| 913 |
+
scale_ui(self, custom_scale_width=450, custom_scale_height=125)
|
| 914 |
+
except Exception as e:
|
| 915 |
+
show_error("Error initializing loading_window class in ncbi tool.", e)
|
|
@@ -1,9 +1,9 @@
|
|
| 1 |
from PyQt5 import QtWidgets, Qt, QtGui, QtCore, uic
|
| 2 |
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg
|
| 3 |
from matplotlib.figure import Figure
|
| 4 |
-
import GlobalSettings
|
| 5 |
import os
|
| 6 |
-
import Algorithms
|
| 7 |
import numpy as np
|
| 8 |
from PyQt5.QtWidgets import *
|
| 9 |
import gzip
|
|
@@ -12,21 +12,15 @@ import itertools
|
|
| 12 |
import matplotlib.patches as patches
|
| 13 |
import mplcursors
|
| 14 |
import copy
|
| 15 |
-
import
|
| 16 |
-
import math
|
| 17 |
|
| 18 |
-
#global logger
|
| 19 |
logger = GlobalSettings.logger
|
| 20 |
|
| 21 |
-
|
| 22 |
-
#population analysis class
|
| 23 |
class Pop_Analysis(QtWidgets.QMainWindow):
|
| 24 |
-
|
| 25 |
-
#init class
|
| 26 |
def __init__(self):
|
| 27 |
try:
|
| 28 |
super(Pop_Analysis, self).__init__()
|
| 29 |
-
uic.loadUi(GlobalSettings.appdir + 'pop.ui', self)
|
| 30 |
self.setWindowIcon(Qt.QIcon(GlobalSettings.appdir + "cas9image.ico"))
|
| 31 |
self.goBackButton.clicked.connect(self.go_back)
|
| 32 |
self.analyze_button.clicked.connect(self.pre_analyze)
|
|
@@ -45,7 +39,6 @@ class Pop_Analysis(QtWidgets.QMainWindow):
|
|
| 45 |
self.colormap_layout.setContentsMargins(0,0,0,0)
|
| 46 |
self.colormap_canvas = MplCanvas(self) ###Initialize new Canvas
|
| 47 |
|
| 48 |
-
|
| 49 |
groupbox_style = """
|
| 50 |
QGroupBox:title{subcontrol-origin: margin;
|
| 51 |
left: 10px;
|
|
@@ -107,160 +100,34 @@ class Pop_Analysis(QtWidgets.QMainWindow):
|
|
| 107 |
self.index_to_db = {}
|
| 108 |
self.name_to_db = {}
|
| 109 |
self.cspr_files = []
|
| 110 |
-
self.db_files = []
|
| 111 |
-
self.Endos = {}
|
| 112 |
self.seeds = []
|
| 113 |
|
| 114 |
self.loading_window = loading_window()
|
| 115 |
|
| 116 |
-
#scale UI
|
| 117 |
self.first_show = True
|
| 118 |
-
self
|
| 119 |
|
| 120 |
except Exception as e:
|
| 121 |
-
|
| 122 |
-
logger.critical(e)
|
| 123 |
-
logger.critical(traceback.format_exc())
|
| 124 |
-
msgBox = QtWidgets.QMessageBox()
|
| 125 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 126 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 127 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 128 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 129 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 130 |
-
msgBox.exec()
|
| 131 |
-
|
| 132 |
-
|
| 133 |
-
exit(-1)
|
| 134 |
-
|
| 135 |
-
#scale the UI based on current screen
|
| 136 |
-
def scaleUI(self):
|
| 137 |
-
try:
|
| 138 |
-
self.repaint()
|
| 139 |
-
QtWidgets.QApplication.processEvents()
|
| 140 |
-
|
| 141 |
-
screen = QtWidgets.QApplication.desktop().screenNumber(QtWidgets.QApplication.desktop().cursor().pos())
|
| 142 |
-
screen = QtWidgets.QApplication.screens()[screen]
|
| 143 |
-
dpi = screen.physicalDotsPerInch()
|
| 144 |
-
self.dpi = dpi
|
| 145 |
-
width = screen.geometry().width()
|
| 146 |
-
height = screen.geometry().height()
|
| 147 |
-
|
| 148 |
-
# font scaling
|
| 149 |
-
fontSize = 12
|
| 150 |
-
self.fontSize = fontSize
|
| 151 |
-
self.centralWidget().setStyleSheet("font: " + str(fontSize) + "pt 'Arial';")
|
| 152 |
-
self.menuBar().setStyleSheet("font: " + str(fontSize) + "pt 'Arial';")
|
| 153 |
-
|
| 154 |
-
# CASPER header scaling
|
| 155 |
-
fontSize = 30
|
| 156 |
-
self.title.setStyleSheet("font: bold " + str(fontSize) + "pt 'Arial';")
|
| 157 |
-
|
| 158 |
-
self.groupBox.setMaximumWidth(int(width * 0.3))
|
| 159 |
-
|
| 160 |
-
self.adjustSize()
|
| 161 |
-
|
| 162 |
-
currentWidth = self.size().width()
|
| 163 |
-
currentHeight = self.size().height()
|
| 164 |
-
|
| 165 |
-
# window scaling
|
| 166 |
-
# 1920x1080 => 1150x650
|
| 167 |
-
scaledWidth = int((width * 1150) / 1920)
|
| 168 |
-
scaledHeight = int((height * 650) / 1080)
|
| 169 |
-
|
| 170 |
-
if scaledHeight < currentHeight:
|
| 171 |
-
scaledHeight = currentHeight
|
| 172 |
-
if scaledWidth < currentWidth:
|
| 173 |
-
scaledWidth = currentWidth
|
| 174 |
-
|
| 175 |
-
screen = QtWidgets.QApplication.desktop().screenNumber(QtWidgets.QApplication.desktop().cursor().pos())
|
| 176 |
-
centerPoint = QtWidgets.QApplication.desktop().screenGeometry(screen).center()
|
| 177 |
-
x = centerPoint.x()
|
| 178 |
-
y = centerPoint.y()
|
| 179 |
-
x = x - (math.ceil(scaledWidth / 2))
|
| 180 |
-
y = y - (math.ceil(scaledHeight / 2))
|
| 181 |
-
self.setGeometry(x, y, scaledWidth, scaledHeight)
|
| 182 |
-
self.repaint()
|
| 183 |
-
QtWidgets.QApplication.processEvents()
|
| 184 |
-
|
| 185 |
-
except Exception as e:
|
| 186 |
-
logger.critical("Error in scaleUI() in population analysis.")
|
| 187 |
-
logger.critical(e)
|
| 188 |
-
logger.critical(traceback.format_exc())
|
| 189 |
-
msgBox = QtWidgets.QMessageBox()
|
| 190 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 191 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 192 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 193 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 194 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 195 |
-
msgBox.exec()
|
| 196 |
-
|
| 197 |
-
|
| 198 |
-
exit(-1)
|
| 199 |
-
|
| 200 |
-
#center UI on current screen
|
| 201 |
-
def centerUI(self):
|
| 202 |
-
try:
|
| 203 |
-
self.repaint()
|
| 204 |
-
QtWidgets.QApplication.processEvents()
|
| 205 |
-
|
| 206 |
-
#center window on current screen
|
| 207 |
-
width = self.width()
|
| 208 |
-
height = self.height()
|
| 209 |
-
screen = QtWidgets.QApplication.desktop().screenNumber(QtWidgets.QApplication.desktop().cursor().pos())
|
| 210 |
-
centerPoint = QtWidgets.QApplication.desktop().screenGeometry(screen).center()
|
| 211 |
-
x = centerPoint.x()
|
| 212 |
-
y = centerPoint.y()
|
| 213 |
-
x = x - (math.ceil(width / 2))
|
| 214 |
-
y = y - (math.ceil(height / 2))
|
| 215 |
-
self.setGeometry(x, y, width, height)
|
| 216 |
-
|
| 217 |
-
self.repaint()
|
| 218 |
-
QtWidgets.QApplication.processEvents()
|
| 219 |
-
except Exception as e:
|
| 220 |
-
logger.critical("Error in centerUI() in population analysis.")
|
| 221 |
-
logger.critical(e)
|
| 222 |
-
logger.critical(traceback.format_exc())
|
| 223 |
-
msgBox = QtWidgets.QMessageBox()
|
| 224 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 225 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 226 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 227 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 228 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 229 |
-
msgBox.exec()
|
| 230 |
-
|
| 231 |
-
|
| 232 |
-
exit(-1)
|
| 233 |
|
| 234 |
#export shared seed table to csv function
|
| 235 |
def export_tool(self):
|
| 236 |
try:
|
| 237 |
select_items = self.table2.selectedItems()
|
| 238 |
-
if len(select_items) <= 0:
|
| 239 |
-
msgBox = QtWidgets.QMessageBox()
|
| 240 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 241 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 242 |
-
msgBox.setWindowTitle("Nothing Selected")
|
| 243 |
-
msgBox.setText("No targets were highlighted. Please highlight the targets you want to be exported to a CSV File!")
|
| 244 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Ok)
|
| 245 |
-
msgBox.exec()
|
| 246 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 247 |
return
|
|
|
|
| 248 |
GlobalSettings.mainWindow.export_tool_window.launch(select_items,"pa")
|
| 249 |
except Exception as e:
|
| 250 |
-
|
| 251 |
-
|
| 252 |
-
logger.critical(traceback.format_exc())
|
| 253 |
-
msgBox = QtWidgets.QMessageBox()
|
| 254 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 255 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 256 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 257 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 258 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 259 |
-
msgBox.exec()
|
| 260 |
-
|
| 261 |
-
|
| 262 |
-
exit(-1)
|
| 263 |
-
|
| 264 |
# this function calls the popParser function and fills all the tables
|
| 265 |
def pre_analyze(self):
|
| 266 |
try:
|
|
@@ -272,16 +139,13 @@ class Pop_Analysis(QtWidgets.QMainWindow):
|
|
| 272 |
#get selected indexes
|
| 273 |
selected_indexes = self.org_Table.selectionModel().selectedRows()
|
| 274 |
|
| 275 |
-
# error check
|
| 276 |
if len(selected_indexes) == 0:
|
| 277 |
-
|
| 278 |
-
|
| 279 |
-
|
| 280 |
-
|
| 281 |
-
|
| 282 |
-
|
| 283 |
-
msgBox.exec()
|
| 284 |
-
|
| 285 |
return
|
| 286 |
|
| 287 |
#get cspr and db filenames
|
|
@@ -293,58 +157,21 @@ class Pop_Analysis(QtWidgets.QMainWindow):
|
|
| 293 |
self.get_org_names()
|
| 294 |
self.fill_data()
|
| 295 |
except Exception as e:
|
| 296 |
-
|
| 297 |
-
|
| 298 |
-
logger.critical(traceback.format_exc())
|
| 299 |
-
msgBox = QtWidgets.QMessageBox()
|
| 300 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 301 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 302 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 303 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 304 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 305 |
-
msgBox.exec()
|
| 306 |
-
|
| 307 |
-
|
| 308 |
-
exit(-1)
|
| 309 |
-
|
| 310 |
-
#wrapper for calling get_data()
|
| 311 |
def launch(self):
|
| 312 |
try:
|
| 313 |
self.get_data()
|
| 314 |
except Exception as e:
|
| 315 |
-
|
| 316 |
-
|
| 317 |
-
logger.critical(traceback.format_exc())
|
| 318 |
-
msgBox = QtWidgets.QMessageBox()
|
| 319 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 320 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 321 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 322 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 323 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 324 |
-
msgBox.exec()
|
| 325 |
-
|
| 326 |
-
|
| 327 |
-
exit(-1)
|
| 328 |
-
|
| 329 |
#responsible for calling all loading/analysis functions for loading the shared seeds table and generating the heatmap based on selected organisms
|
| 330 |
def get_data(self):
|
| 331 |
try:
|
| 332 |
self.fillEndo()
|
| 333 |
except Exception as e:
|
| 334 |
-
|
| 335 |
-
|
| 336 |
-
logger.critical(traceback.format_exc())
|
| 337 |
-
msgBox = QtWidgets.QMessageBox()
|
| 338 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 339 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 340 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 341 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 342 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 343 |
-
msgBox.exec()
|
| 344 |
-
|
| 345 |
-
|
| 346 |
-
exit(-1)
|
| 347 |
-
|
| 348 |
# this function opens CASPERinfo and builds the dropdown menu of selectable endonucleases
|
| 349 |
def fillEndo(self):
|
| 350 |
try:
|
|
@@ -381,20 +208,8 @@ class Pop_Analysis(QtWidgets.QMainWindow):
|
|
| 381 |
self.endoBox.currentIndexChanged.connect(self.change_endo)
|
| 382 |
self.change_endo()
|
| 383 |
except Exception as e:
|
| 384 |
-
|
| 385 |
-
|
| 386 |
-
logger.critical(traceback.format_exc())
|
| 387 |
-
msgBox = QtWidgets.QMessageBox()
|
| 388 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 389 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 390 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 391 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 392 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 393 |
-
msgBox.exec()
|
| 394 |
-
|
| 395 |
-
|
| 396 |
-
exit(-1)
|
| 397 |
-
|
| 398 |
#event handler for updating the organism options based on the endo selected
|
| 399 |
def change_endo(self):
|
| 400 |
try:
|
|
@@ -437,26 +252,14 @@ class Pop_Analysis(QtWidgets.QMainWindow):
|
|
| 437 |
|
| 438 |
self.org_Table.resizeColumnsToContents()
|
| 439 |
except Exception as e:
|
| 440 |
-
|
| 441 |
-
|
| 442 |
-
logger.critical(traceback.format_exc())
|
| 443 |
-
msgBox = QtWidgets.QMessageBox()
|
| 444 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 445 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 446 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 447 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 448 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 449 |
-
msgBox.exec()
|
| 450 |
-
|
| 451 |
-
|
| 452 |
-
exit(-1)
|
| 453 |
-
|
| 454 |
#fills shared seed table with data from analysis
|
| 455 |
def fill_data(self):
|
| 456 |
try:
|
| 457 |
#update progress bar
|
| 458 |
self.loading_window.loading_bar.setValue(5)
|
| 459 |
-
self.loading_window
|
| 460 |
self.loading_window.show()
|
| 461 |
QtCore.QCoreApplication.processEvents()
|
| 462 |
|
|
@@ -510,12 +313,14 @@ class Pop_Analysis(QtWidgets.QMainWindow):
|
|
| 510 |
data = c.execute("SELECT count, three, five, pam, score, location FROM repeats WHERE seed = ? ",(seed,)).fetchone()
|
| 511 |
if data != None:
|
| 512 |
data = list(data)
|
|
|
|
| 513 |
org_count += 1
|
| 514 |
total_count += int(data[0])
|
| 515 |
threes += data[1].split(",")
|
| 516 |
fives += data[2].split(",")
|
| 517 |
pams += data[3].split(",")
|
| 518 |
scores += data[4].split(",")
|
|
|
|
| 519 |
locs += data[5].split(",")
|
| 520 |
|
| 521 |
self.counts.append(total_count)
|
|
@@ -629,19 +434,7 @@ class Pop_Analysis(QtWidgets.QMainWindow):
|
|
| 629 |
self.loading_window.hide()
|
| 630 |
QtCore.QCoreApplication.processEvents()
|
| 631 |
except Exception as e:
|
| 632 |
-
|
| 633 |
-
logger.critical(e)
|
| 634 |
-
logger.critical(traceback.format_exc())
|
| 635 |
-
msgBox = QtWidgets.QMessageBox()
|
| 636 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 637 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 638 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 639 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 640 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 641 |
-
msgBox.exec()
|
| 642 |
-
|
| 643 |
-
|
| 644 |
-
exit(-1)
|
| 645 |
|
| 646 |
#function to allow user to search for a specific seed amongst the organisms analyzed
|
| 647 |
def custom_seed_search(self):
|
|
@@ -672,13 +465,12 @@ class Pop_Analysis(QtWidgets.QMainWindow):
|
|
| 672 |
|
| 673 |
if len(self.seeds) == 0:
|
| 674 |
self.loading_window.hide()
|
| 675 |
-
|
| 676 |
-
|
| 677 |
-
|
| 678 |
-
|
| 679 |
-
|
| 680 |
-
|
| 681 |
-
msgBox.exec()
|
| 682 |
return
|
| 683 |
|
| 684 |
increase_val = float(15 / len(self.seeds))
|
|
@@ -717,13 +509,12 @@ class Pop_Analysis(QtWidgets.QMainWindow):
|
|
| 717 |
|
| 718 |
if none_data == True:
|
| 719 |
self.loading_window.hide()
|
| 720 |
-
|
| 721 |
-
|
| 722 |
-
|
| 723 |
-
|
| 724 |
-
|
| 725 |
-
|
| 726 |
-
msgBox.exec()
|
| 727 |
return
|
| 728 |
|
| 729 |
else:
|
|
@@ -839,24 +630,11 @@ class Pop_Analysis(QtWidgets.QMainWindow):
|
|
| 839 |
self.loading_window.hide()
|
| 840 |
QtCore.QCoreApplication.processEvents()
|
| 841 |
except Exception as e:
|
| 842 |
-
|
| 843 |
-
|
| 844 |
-
logger.critical(traceback.format_exc())
|
| 845 |
-
msgBox = QtWidgets.QMessageBox()
|
| 846 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 847 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 848 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 849 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 850 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 851 |
-
msgBox.exec()
|
| 852 |
-
|
| 853 |
-
|
| 854 |
-
exit(-1)
|
| 855 |
-
|
| 856 |
#db_files is an array of database files for the organisms that will be looked at for shared seeds
|
| 857 |
def get_shared_seeds(self, db_files, limit=False):
|
| 858 |
try:
|
| 859 |
-
#vars
|
| 860 |
aliases = []
|
| 861 |
|
| 862 |
#get db attachment aliases
|
|
@@ -912,20 +690,8 @@ class Pop_Analysis(QtWidgets.QMainWindow):
|
|
| 912 |
return seeds
|
| 913 |
|
| 914 |
except Exception as e:
|
| 915 |
-
|
| 916 |
-
|
| 917 |
-
logger.critical(traceback.format_exc())
|
| 918 |
-
msgBox = QtWidgets.QMessageBox()
|
| 919 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 920 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 921 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 922 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 923 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 924 |
-
msgBox.exec()
|
| 925 |
-
|
| 926 |
-
|
| 927 |
-
exit(-1)
|
| 928 |
-
|
| 929 |
#get the names of organism in current directory
|
| 930 |
def get_org_names(self):
|
| 931 |
try:
|
|
@@ -943,20 +709,8 @@ class Pop_Analysis(QtWidgets.QMainWindow):
|
|
| 943 |
kstats = kstats.split(",")
|
| 944 |
self.org_names[org_name] = len(kstats) - 1
|
| 945 |
except Exception as e:
|
| 946 |
-
|
| 947 |
-
|
| 948 |
-
logger.critical(traceback.format_exc())
|
| 949 |
-
msgBox = QtWidgets.QMessageBox()
|
| 950 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 951 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 952 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 953 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 954 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 955 |
-
msgBox.exec()
|
| 956 |
-
|
| 957 |
-
|
| 958 |
-
exit(-1)
|
| 959 |
-
|
| 960 |
#plot the heatmap graph
|
| 961 |
def plot_3D_graph(self):
|
| 962 |
try:
|
|
@@ -1028,34 +782,18 @@ class Pop_Analysis(QtWidgets.QMainWindow):
|
|
| 1028 |
|
| 1029 |
self.colormap_canvas.draw()
|
| 1030 |
except Exception as e:
|
| 1031 |
-
|
| 1032 |
-
logger.critical(e)
|
| 1033 |
-
logger.critical(traceback.format_exc())
|
| 1034 |
-
msgBox = QtWidgets.QMessageBox()
|
| 1035 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 1036 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 1037 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 1038 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 1039 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 1040 |
-
msgBox.exec()
|
| 1041 |
-
|
| 1042 |
-
|
| 1043 |
-
exit(-1)
|
| 1044 |
|
| 1045 |
#find the locations of selected seeds to load into the location table
|
| 1046 |
def find_locations(self):
|
| 1047 |
try:
|
| 1048 |
-
#error checking
|
| 1049 |
if len(self.table2.selectedItems()) == 0:
|
| 1050 |
-
|
| 1051 |
-
|
| 1052 |
-
|
| 1053 |
-
|
| 1054 |
-
|
| 1055 |
-
|
| 1056 |
-
msgBox.exec()
|
| 1057 |
-
|
| 1058 |
-
self.loc_finder_table.setRowCount(0)
|
| 1059 |
return
|
| 1060 |
|
| 1061 |
#get seeds from selected rows in table
|
|
@@ -1111,19 +849,7 @@ class Pop_Analysis(QtWidgets.QMainWindow):
|
|
| 1111 |
|
| 1112 |
self.loc_finder_table.resizeColumnsToContents()
|
| 1113 |
except Exception as e:
|
| 1114 |
-
|
| 1115 |
-
logger.critical(e)
|
| 1116 |
-
logger.critical(traceback.format_exc())
|
| 1117 |
-
msgBox = QtWidgets.QMessageBox()
|
| 1118 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 1119 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 1120 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 1121 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 1122 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 1123 |
-
msgBox.exec()
|
| 1124 |
-
|
| 1125 |
-
|
| 1126 |
-
exit(-1)
|
| 1127 |
|
| 1128 |
# this function clears the loc_finder_table
|
| 1129 |
def clear_loc_table(self):
|
|
@@ -1131,20 +857,8 @@ class Pop_Analysis(QtWidgets.QMainWindow):
|
|
| 1131 |
self.loc_finder_table.clearContents()
|
| 1132 |
self.loc_finder_table.setRowCount(0)
|
| 1133 |
except Exception as e:
|
| 1134 |
-
|
| 1135 |
-
|
| 1136 |
-
logger.critical(traceback.format_exc())
|
| 1137 |
-
msgBox = QtWidgets.QMessageBox()
|
| 1138 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 1139 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 1140 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 1141 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 1142 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 1143 |
-
msgBox.exec()
|
| 1144 |
-
|
| 1145 |
-
|
| 1146 |
-
exit(-1)
|
| 1147 |
-
|
| 1148 |
# sorting function for table2 - shared seeds table: IE the table in top-right
|
| 1149 |
def table2_sorting(self, logicalIndex):
|
| 1150 |
try:
|
|
@@ -1154,19 +868,7 @@ class Pop_Analysis(QtWidgets.QMainWindow):
|
|
| 1154 |
else:
|
| 1155 |
self.table2.sortItems(logicalIndex, QtCore.Qt.AscendingOrder)
|
| 1156 |
except Exception as e:
|
| 1157 |
-
|
| 1158 |
-
logger.critical(e)
|
| 1159 |
-
logger.critical(traceback.format_exc())
|
| 1160 |
-
msgBox = QtWidgets.QMessageBox()
|
| 1161 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 1162 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 1163 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 1164 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 1165 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 1166 |
-
msgBox.exec()
|
| 1167 |
-
|
| 1168 |
-
|
| 1169 |
-
exit(-1)
|
| 1170 |
|
| 1171 |
# sorting for location table: IE table in bottom right
|
| 1172 |
def loc_table_sorter(self, logicalIndex):
|
|
@@ -1177,58 +879,22 @@ class Pop_Analysis(QtWidgets.QMainWindow):
|
|
| 1177 |
else:
|
| 1178 |
self.loc_finder_table.sortItems(logicalIndex, QtCore.Qt.AscendingOrder)
|
| 1179 |
except Exception as e:
|
| 1180 |
-
|
| 1181 |
-
|
| 1182 |
-
logger.critical(traceback.format_exc())
|
| 1183 |
-
msgBox = QtWidgets.QMessageBox()
|
| 1184 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 1185 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 1186 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 1187 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 1188 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 1189 |
-
msgBox.exec()
|
| 1190 |
-
|
| 1191 |
-
|
| 1192 |
-
exit(-1)
|
| 1193 |
-
|
| 1194 |
#clears the table showcasing shared seeds
|
| 1195 |
def clear(self):
|
| 1196 |
try:
|
| 1197 |
self.table2.setRowCount(0)
|
| 1198 |
except Exception as e:
|
| 1199 |
-
|
| 1200 |
-
|
| 1201 |
-
logger.critical(traceback.format_exc())
|
| 1202 |
-
msgBox = QtWidgets.QMessageBox()
|
| 1203 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 1204 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 1205 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 1206 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 1207 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 1208 |
-
msgBox.exec()
|
| 1209 |
-
|
| 1210 |
-
|
| 1211 |
-
exit(-1)
|
| 1212 |
-
|
| 1213 |
#return to main function
|
| 1214 |
def go_back(self):
|
| 1215 |
try:
|
| 1216 |
GlobalSettings.mainWindow.show()
|
| 1217 |
self.hide()
|
| 1218 |
except Exception as e:
|
| 1219 |
-
|
| 1220 |
-
logger.critical(e)
|
| 1221 |
-
logger.critical(traceback.format_exc())
|
| 1222 |
-
msgBox = QtWidgets.QMessageBox()
|
| 1223 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 1224 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 1225 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 1226 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 1227 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 1228 |
-
msgBox.exec()
|
| 1229 |
-
|
| 1230 |
-
|
| 1231 |
-
exit(-1)
|
| 1232 |
|
| 1233 |
# this function calls the close window class. Allows the user to choose what files they want to keep/delete
|
| 1234 |
def closeEvent(self, event):
|
|
@@ -1236,134 +902,20 @@ class Pop_Analysis(QtWidgets.QMainWindow):
|
|
| 1236 |
GlobalSettings.mainWindow.closeFunction()
|
| 1237 |
event.accept()
|
| 1238 |
except Exception as e:
|
| 1239 |
-
|
| 1240 |
-
|
| 1241 |
-
logger.critical(traceback.format_exc())
|
| 1242 |
-
msgBox = QtWidgets.QMessageBox()
|
| 1243 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 1244 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 1245 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 1246 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 1247 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 1248 |
-
msgBox.exec()
|
| 1249 |
-
|
| 1250 |
-
|
| 1251 |
-
exit(-1)
|
| 1252 |
-
|
| 1253 |
-
|
| 1254 |
#loading window UI class for when data is loading
|
| 1255 |
class loading_window(QtWidgets.QMainWindow):
|
| 1256 |
def __init__(self):
|
| 1257 |
try:
|
| 1258 |
super(loading_window, self).__init__()
|
| 1259 |
-
uic.loadUi(GlobalSettings.appdir + "loading_data_form.ui", self)
|
| 1260 |
self.loading_bar.setValue(0)
|
| 1261 |
self.setWindowTitle("Loading Data")
|
| 1262 |
self.setWindowIcon(Qt.QIcon(GlobalSettings.appdir + "cas9image.ico"))
|
| 1263 |
-
self
|
| 1264 |
except Exception as e:
|
| 1265 |
-
|
| 1266 |
-
logger.critical(e)
|
| 1267 |
-
logger.critical(traceback.format_exc())
|
| 1268 |
-
msgBox = QtWidgets.QMessageBox()
|
| 1269 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 1270 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 1271 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 1272 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 1273 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 1274 |
-
msgBox.exec()
|
| 1275 |
-
|
| 1276 |
-
|
| 1277 |
-
exit(-1)
|
| 1278 |
-
|
| 1279 |
-
#scale UI based on current screen
|
| 1280 |
-
def scaleUI(self):
|
| 1281 |
-
try:
|
| 1282 |
-
self.repaint()
|
| 1283 |
-
QtWidgets.QApplication.processEvents()
|
| 1284 |
-
|
| 1285 |
-
screen = self.screen()
|
| 1286 |
-
dpi = screen.physicalDotsPerInch()
|
| 1287 |
-
width = screen.geometry().width()
|
| 1288 |
-
height = screen.geometry().height()
|
| 1289 |
-
|
| 1290 |
-
# font scaling
|
| 1291 |
-
fontSize = 12
|
| 1292 |
-
self.centralWidget().setStyleSheet("font: " + str(fontSize) + "pt 'Arial';")
|
| 1293 |
-
|
| 1294 |
-
self.adjustSize()
|
| 1295 |
-
|
| 1296 |
-
currentWidth = self.size().width()
|
| 1297 |
-
currentHeight = self.size().height()
|
| 1298 |
-
|
| 1299 |
-
# scale/center window
|
| 1300 |
-
scaledWidth = int((width * 450) / 1920)
|
| 1301 |
-
scaledHeight = int((height * 125) / 1080)
|
| 1302 |
-
|
| 1303 |
-
if scaledHeight < currentHeight:
|
| 1304 |
-
scaledHeight = currentHeight
|
| 1305 |
-
if scaledWidth < currentWidth:
|
| 1306 |
-
scaledWidth = currentWidth
|
| 1307 |
-
|
| 1308 |
-
screen = QtWidgets.QApplication.desktop().screenNumber(QtWidgets.QApplication.desktop().cursor().pos())
|
| 1309 |
-
centerPoint = QtWidgets.QApplication.desktop().screenGeometry(screen).center()
|
| 1310 |
-
x = centerPoint.x()
|
| 1311 |
-
y = centerPoint.y()
|
| 1312 |
-
x = x - (math.ceil(scaledWidth / 2))
|
| 1313 |
-
y = y - (math.ceil(scaledHeight / 2))
|
| 1314 |
-
self.setGeometry(x, y, scaledWidth, scaledHeight)
|
| 1315 |
-
|
| 1316 |
-
self.repaint()
|
| 1317 |
-
QtWidgets.QApplication.processEvents()
|
| 1318 |
-
except Exception as e:
|
| 1319 |
-
logger.critical("Error in scaleUI() in loading_window() class in population analysis.")
|
| 1320 |
-
logger.critical(e)
|
| 1321 |
-
logger.critical(traceback.format_exc())
|
| 1322 |
-
msgBox = QtWidgets.QMessageBox()
|
| 1323 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 1324 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 1325 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 1326 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 1327 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 1328 |
-
msgBox.exec()
|
| 1329 |
-
|
| 1330 |
-
|
| 1331 |
-
exit(-1)
|
| 1332 |
-
|
| 1333 |
-
#center UI on current screen
|
| 1334 |
-
def centerUI(self):
|
| 1335 |
-
try:
|
| 1336 |
-
self.repaint()
|
| 1337 |
-
QtWidgets.QApplication.processEvents()
|
| 1338 |
-
|
| 1339 |
-
width = self.width()
|
| 1340 |
-
height = self.height()
|
| 1341 |
-
#scale/center window
|
| 1342 |
-
screen = QtWidgets.QApplication.desktop().screenNumber(QtWidgets.QApplication.desktop().cursor().pos())
|
| 1343 |
-
centerPoint = QtWidgets.QApplication.desktop().screenGeometry(screen).center()
|
| 1344 |
-
x = centerPoint.x()
|
| 1345 |
-
y = centerPoint.y()
|
| 1346 |
-
x = x - (math.ceil(width / 2))
|
| 1347 |
-
y = y - (math.ceil(height / 2))
|
| 1348 |
-
self.setGeometry(x, y, width, height)
|
| 1349 |
-
|
| 1350 |
-
self.repaint()
|
| 1351 |
-
QtWidgets.QApplication.processEvents()
|
| 1352 |
-
except Exception as e:
|
| 1353 |
-
logger.critical("Error in centerUI() in loading_window() class in population analysis.")
|
| 1354 |
-
logger.critical(e)
|
| 1355 |
-
logger.critical(traceback.format_exc())
|
| 1356 |
-
msgBox = QtWidgets.QMessageBox()
|
| 1357 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 1358 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 1359 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 1360 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 1361 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 1362 |
-
msgBox.exec()
|
| 1363 |
-
|
| 1364 |
-
|
| 1365 |
-
exit(-1)
|
| 1366 |
-
|
| 1367 |
|
| 1368 |
#matplotlib canvas class for the heatmap graph
|
| 1369 |
class MplCanvas(FigureCanvasQTAgg):
|
|
@@ -1374,16 +926,4 @@ class MplCanvas(FigureCanvasQTAgg):
|
|
| 1374 |
self.axes.clear()
|
| 1375 |
super(MplCanvas, self).__init__(fig)
|
| 1376 |
except Exception as e:
|
| 1377 |
-
|
| 1378 |
-
logger.critical(e)
|
| 1379 |
-
logger.critical(traceback.format_exc())
|
| 1380 |
-
msgBox = QtWidgets.QMessageBox()
|
| 1381 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 1382 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 1383 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 1384 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 1385 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 1386 |
-
msgBox.exec()
|
| 1387 |
-
|
| 1388 |
-
|
| 1389 |
-
exit(-1)
|
|
|
|
| 1 |
from PyQt5 import QtWidgets, Qt, QtGui, QtCore, uic
|
| 2 |
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg
|
| 3 |
from matplotlib.figure import Figure
|
| 4 |
+
import models.GlobalSettings as GlobalSettings
|
| 5 |
import os
|
| 6 |
+
import utils.Algorithms as Algorithms
|
| 7 |
import numpy as np
|
| 8 |
from PyQt5.QtWidgets import *
|
| 9 |
import gzip
|
|
|
|
| 12 |
import matplotlib.patches as patches
|
| 13 |
import mplcursors
|
| 14 |
import copy
|
| 15 |
+
from utils.ui import show_error, scale_ui, center_ui, show_message
|
|
|
|
| 16 |
|
|
|
|
| 17 |
logger = GlobalSettings.logger
|
| 18 |
|
|
|
|
|
|
|
| 19 |
class Pop_Analysis(QtWidgets.QMainWindow):
|
|
|
|
|
|
|
| 20 |
def __init__(self):
|
| 21 |
try:
|
| 22 |
super(Pop_Analysis, self).__init__()
|
| 23 |
+
uic.loadUi(GlobalSettings.appdir + 'ui/pop.ui', self)
|
| 24 |
self.setWindowIcon(Qt.QIcon(GlobalSettings.appdir + "cas9image.ico"))
|
| 25 |
self.goBackButton.clicked.connect(self.go_back)
|
| 26 |
self.analyze_button.clicked.connect(self.pre_analyze)
|
|
|
|
| 39 |
self.colormap_layout.setContentsMargins(0,0,0,0)
|
| 40 |
self.colormap_canvas = MplCanvas(self) ###Initialize new Canvas
|
| 41 |
|
|
|
|
| 42 |
groupbox_style = """
|
| 43 |
QGroupBox:title{subcontrol-origin: margin;
|
| 44 |
left: 10px;
|
|
|
|
| 100 |
self.index_to_db = {}
|
| 101 |
self.name_to_db = {}
|
| 102 |
self.cspr_files = []
|
|
|
|
|
|
|
| 103 |
self.seeds = []
|
| 104 |
|
| 105 |
self.loading_window = loading_window()
|
| 106 |
|
|
|
|
| 107 |
self.first_show = True
|
| 108 |
+
scale_ui(self, base_width=1920, base_height=1080, font_size=12, header_font_size=30)
|
| 109 |
|
| 110 |
except Exception as e:
|
| 111 |
+
show_error("Error initializing population analysis.", e)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 112 |
|
| 113 |
#export shared seed table to csv function
|
| 114 |
def export_tool(self):
|
| 115 |
try:
|
| 116 |
select_items = self.table2.selectedItems()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 117 |
|
| 118 |
+
if len(select_items) <= 0:
|
| 119 |
+
show_message(
|
| 120 |
+
fontSize=12,
|
| 121 |
+
icon=QtWidgets.QMessageBox.Icon.Critical,
|
| 122 |
+
title="Nothing Selected",
|
| 123 |
+
message="No targets were highlighted. Please highlight the targets you want to be exported to a CSV File!"
|
| 124 |
+
)
|
| 125 |
return
|
| 126 |
+
|
| 127 |
GlobalSettings.mainWindow.export_tool_window.launch(select_items,"pa")
|
| 128 |
except Exception as e:
|
| 129 |
+
show_error("Error in export_tool() in population analysis.", e)
|
| 130 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 131 |
# this function calls the popParser function and fills all the tables
|
| 132 |
def pre_analyze(self):
|
| 133 |
try:
|
|
|
|
| 139 |
#get selected indexes
|
| 140 |
selected_indexes = self.org_Table.selectionModel().selectedRows()
|
| 141 |
|
|
|
|
| 142 |
if len(selected_indexes) == 0:
|
| 143 |
+
show_message(
|
| 144 |
+
fontSize=12,
|
| 145 |
+
icon=QtWidgets.QMessageBox.Icon.Critical,
|
| 146 |
+
title="Error",
|
| 147 |
+
message="Please select CSPR file(s) for analysis."
|
| 148 |
+
)
|
|
|
|
|
|
|
| 149 |
return
|
| 150 |
|
| 151 |
#get cspr and db filenames
|
|
|
|
| 157 |
self.get_org_names()
|
| 158 |
self.fill_data()
|
| 159 |
except Exception as e:
|
| 160 |
+
show_error("Error in pre_analyze() in population analysis.", e)
|
| 161 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 162 |
def launch(self):
|
| 163 |
try:
|
| 164 |
self.get_data()
|
| 165 |
except Exception as e:
|
| 166 |
+
show_error("Error in launch() in population analysis.", e)
|
| 167 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 168 |
#responsible for calling all loading/analysis functions for loading the shared seeds table and generating the heatmap based on selected organisms
|
| 169 |
def get_data(self):
|
| 170 |
try:
|
| 171 |
self.fillEndo()
|
| 172 |
except Exception as e:
|
| 173 |
+
show_error("Error in get_data() in population analysis.", e)
|
| 174 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 175 |
# this function opens CASPERinfo and builds the dropdown menu of selectable endonucleases
|
| 176 |
def fillEndo(self):
|
| 177 |
try:
|
|
|
|
| 208 |
self.endoBox.currentIndexChanged.connect(self.change_endo)
|
| 209 |
self.change_endo()
|
| 210 |
except Exception as e:
|
| 211 |
+
show_error("Error in fillEndo() in population analysis.", e)
|
| 212 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 213 |
#event handler for updating the organism options based on the endo selected
|
| 214 |
def change_endo(self):
|
| 215 |
try:
|
|
|
|
| 252 |
|
| 253 |
self.org_Table.resizeColumnsToContents()
|
| 254 |
except Exception as e:
|
| 255 |
+
show_error("Error in change_endo() in population analysis.", e)
|
| 256 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 257 |
#fills shared seed table with data from analysis
|
| 258 |
def fill_data(self):
|
| 259 |
try:
|
| 260 |
#update progress bar
|
| 261 |
self.loading_window.loading_bar.setValue(5)
|
| 262 |
+
center_ui(self.loading_window)
|
| 263 |
self.loading_window.show()
|
| 264 |
QtCore.QCoreApplication.processEvents()
|
| 265 |
|
|
|
|
| 313 |
data = c.execute("SELECT count, three, five, pam, score, location FROM repeats WHERE seed = ? ",(seed,)).fetchone()
|
| 314 |
if data != None:
|
| 315 |
data = list(data)
|
| 316 |
+
print(data)
|
| 317 |
org_count += 1
|
| 318 |
total_count += int(data[0])
|
| 319 |
threes += data[1].split(",")
|
| 320 |
fives += data[2].split(",")
|
| 321 |
pams += data[3].split(",")
|
| 322 |
scores += data[4].split(",")
|
| 323 |
+
print(scores)
|
| 324 |
locs += data[5].split(",")
|
| 325 |
|
| 326 |
self.counts.append(total_count)
|
|
|
|
| 434 |
self.loading_window.hide()
|
| 435 |
QtCore.QCoreApplication.processEvents()
|
| 436 |
except Exception as e:
|
| 437 |
+
show_error("Error in fill_data() in population analysis.", e)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 438 |
|
| 439 |
#function to allow user to search for a specific seed amongst the organisms analyzed
|
| 440 |
def custom_seed_search(self):
|
|
|
|
| 465 |
|
| 466 |
if len(self.seeds) == 0:
|
| 467 |
self.loading_window.hide()
|
| 468 |
+
show_message(
|
| 469 |
+
fontSize=12,
|
| 470 |
+
icon=QtWidgets.QMessageBox.Icon.Critical,
|
| 471 |
+
title="Error",
|
| 472 |
+
message="No analysis has been run to be able to search for a specific seed."
|
| 473 |
+
)
|
|
|
|
| 474 |
return
|
| 475 |
|
| 476 |
increase_val = float(15 / len(self.seeds))
|
|
|
|
| 509 |
|
| 510 |
if none_data == True:
|
| 511 |
self.loading_window.hide()
|
| 512 |
+
show_message(
|
| 513 |
+
fontSize=12,
|
| 514 |
+
icon=QtWidgets.QMessageBox.Icon.Critical,
|
| 515 |
+
title="Seed Error",
|
| 516 |
+
message=seed + " : No such seed exists in the repeats section of any organism selected."
|
| 517 |
+
)
|
|
|
|
| 518 |
return
|
| 519 |
|
| 520 |
else:
|
|
|
|
| 630 |
self.loading_window.hide()
|
| 631 |
QtCore.QCoreApplication.processEvents()
|
| 632 |
except Exception as e:
|
| 633 |
+
show_error("Error in custom_seed_search() in population analysis.", e)
|
| 634 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 635 |
#db_files is an array of database files for the organisms that will be looked at for shared seeds
|
| 636 |
def get_shared_seeds(self, db_files, limit=False):
|
| 637 |
try:
|
|
|
|
| 638 |
aliases = []
|
| 639 |
|
| 640 |
#get db attachment aliases
|
|
|
|
| 690 |
return seeds
|
| 691 |
|
| 692 |
except Exception as e:
|
| 693 |
+
show_error("Error in get_shared_seeds() in population analysis.", e)
|
| 694 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 695 |
#get the names of organism in current directory
|
| 696 |
def get_org_names(self):
|
| 697 |
try:
|
|
|
|
| 709 |
kstats = kstats.split(",")
|
| 710 |
self.org_names[org_name] = len(kstats) - 1
|
| 711 |
except Exception as e:
|
| 712 |
+
show_error("Error in get_org_names() in population analysis.", e)
|
| 713 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 714 |
#plot the heatmap graph
|
| 715 |
def plot_3D_graph(self):
|
| 716 |
try:
|
|
|
|
| 782 |
|
| 783 |
self.colormap_canvas.draw()
|
| 784 |
except Exception as e:
|
| 785 |
+
show_error("Error in plot_3D_graph() in population analysis.", e)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 786 |
|
| 787 |
#find the locations of selected seeds to load into the location table
|
| 788 |
def find_locations(self):
|
| 789 |
try:
|
|
|
|
| 790 |
if len(self.table2.selectedItems()) == 0:
|
| 791 |
+
show_message(
|
| 792 |
+
fontSize=12,
|
| 793 |
+
icon=QtWidgets.QMessageBox.Icon.Critical,
|
| 794 |
+
title="Error",
|
| 795 |
+
message="Please select at least 1 seed to find locations of."
|
| 796 |
+
)
|
|
|
|
|
|
|
|
|
|
| 797 |
return
|
| 798 |
|
| 799 |
#get seeds from selected rows in table
|
|
|
|
| 849 |
|
| 850 |
self.loc_finder_table.resizeColumnsToContents()
|
| 851 |
except Exception as e:
|
| 852 |
+
show_error("Error in find_locations() in population analysis.", e)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 853 |
|
| 854 |
# this function clears the loc_finder_table
|
| 855 |
def clear_loc_table(self):
|
|
|
|
| 857 |
self.loc_finder_table.clearContents()
|
| 858 |
self.loc_finder_table.setRowCount(0)
|
| 859 |
except Exception as e:
|
| 860 |
+
show_error("Error in clear_loc_table() in population analysis.", e)
|
| 861 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 862 |
# sorting function for table2 - shared seeds table: IE the table in top-right
|
| 863 |
def table2_sorting(self, logicalIndex):
|
| 864 |
try:
|
|
|
|
| 868 |
else:
|
| 869 |
self.table2.sortItems(logicalIndex, QtCore.Qt.AscendingOrder)
|
| 870 |
except Exception as e:
|
| 871 |
+
show_error("Error in table2_sorting() in population analysis.", e)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 872 |
|
| 873 |
# sorting for location table: IE table in bottom right
|
| 874 |
def loc_table_sorter(self, logicalIndex):
|
|
|
|
| 879 |
else:
|
| 880 |
self.loc_finder_table.sortItems(logicalIndex, QtCore.Qt.AscendingOrder)
|
| 881 |
except Exception as e:
|
| 882 |
+
show_error("Error in loc_table_sorter() in population analysis.", e)
|
| 883 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 884 |
#clears the table showcasing shared seeds
|
| 885 |
def clear(self):
|
| 886 |
try:
|
| 887 |
self.table2.setRowCount(0)
|
| 888 |
except Exception as e:
|
| 889 |
+
show_error("Error in clear() in population analysis.", e)
|
| 890 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 891 |
#return to main function
|
| 892 |
def go_back(self):
|
| 893 |
try:
|
| 894 |
GlobalSettings.mainWindow.show()
|
| 895 |
self.hide()
|
| 896 |
except Exception as e:
|
| 897 |
+
show_error("Error in go_back() in population analysis.", e)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 898 |
|
| 899 |
# this function calls the close window class. Allows the user to choose what files they want to keep/delete
|
| 900 |
def closeEvent(self, event):
|
|
|
|
| 902 |
GlobalSettings.mainWindow.closeFunction()
|
| 903 |
event.accept()
|
| 904 |
except Exception as e:
|
| 905 |
+
show_error("Error in closeEvent() in population analysis.", e)
|
| 906 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 907 |
#loading window UI class for when data is loading
|
| 908 |
class loading_window(QtWidgets.QMainWindow):
|
| 909 |
def __init__(self):
|
| 910 |
try:
|
| 911 |
super(loading_window, self).__init__()
|
| 912 |
+
uic.loadUi(GlobalSettings.appdir + "ui/loading_data_form.ui", self)
|
| 913 |
self.loading_bar.setValue(0)
|
| 914 |
self.setWindowTitle("Loading Data")
|
| 915 |
self.setWindowIcon(Qt.QIcon(GlobalSettings.appdir + "cas9image.ico"))
|
| 916 |
+
scale_ui(self, base_width=1920, base_height=1080, font_size=12, header_font_size=30, custom_scale_width=450, custom_scale_height=125)
|
| 917 |
except Exception as e:
|
| 918 |
+
show_error("Error initializing loading_window class in population analysis.", e)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 919 |
|
| 920 |
#matplotlib canvas class for the heatmap graph
|
| 921 |
class MplCanvas(FigureCanvasQTAgg):
|
|
|
|
| 926 |
self.axes.clear()
|
| 927 |
super(MplCanvas, self).__init__(fig)
|
| 928 |
except Exception as e:
|
| 929 |
+
show_error("Error initializing MplCanvas class in population analysis.", e)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@@ -1,5 +1,5 @@
|
|
| 1 |
-
from Algorithms import get_table_headers
|
| 2 |
-
import GlobalSettings
|
| 3 |
import azimuth.model_comparison as az
|
| 4 |
from PyQt5 import QtWidgets, uic, QtCore
|
| 5 |
import platform
|
|
@@ -50,7 +50,7 @@ class Scoring_Window(QtWidgets.QMainWindow):
|
|
| 50 |
try:
|
| 51 |
# qt stuff
|
| 52 |
super(Scoring_Window, self).__init__()
|
| 53 |
-
uic.loadUi(GlobalSettings.appdir + 'scoring_window.ui', self)
|
| 54 |
self.progressBar.setValue(0) # Make sure the progress bar starts at 0
|
| 55 |
|
| 56 |
# Button Connections
|
|
|
|
| 1 |
+
from utils.Algorithms import get_table_headers
|
| 2 |
+
import models.GlobalSettings as GlobalSettings
|
| 3 |
import azimuth.model_comparison as az
|
| 4 |
from PyQt5 import QtWidgets, uic, QtCore
|
| 5 |
import platform
|
|
|
|
| 50 |
try:
|
| 51 |
# qt stuff
|
| 52 |
super(Scoring_Window, self).__init__()
|
| 53 |
+
uic.loadUi(GlobalSettings.appdir + 'ui/scoring_window.ui', self)
|
| 54 |
self.progressBar.setValue(0) # Make sure the progress bar starts at 0
|
| 55 |
|
| 56 |
# Button Connections
|
|
@@ -1,21 +0,0 @@
|
|
| 1 |
-
from PyQt5 import QtWidgets
|
| 2 |
-
import traceback
|
| 3 |
-
import GlobalSettings
|
| 4 |
-
from common_utils import show_message
|
| 5 |
-
|
| 6 |
-
#global logger
|
| 7 |
-
logger = GlobalSettings.logger
|
| 8 |
-
|
| 9 |
-
def show_error(message, e):
|
| 10 |
-
logger.critical(message)
|
| 11 |
-
logger.critical(e)
|
| 12 |
-
logger.critical(traceback.format_exc())
|
| 13 |
-
|
| 14 |
-
show_message(
|
| 15 |
-
fontSize=12,
|
| 16 |
-
icon=QtWidgets.QMessageBox.Icon.Critical,
|
| 17 |
-
title="Fatal Error",
|
| 18 |
-
message=f"Fatal Error:\n{str(e)}\n\nFor more information on this error, look at CASPER.log in the application folder."
|
| 19 |
-
)
|
| 20 |
-
|
| 21 |
-
exit(-1)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
File without changes
|
|
@@ -1,1650 +1,24 @@
|
|
| 1 |
-
from Algorithms import get_table_headers
|
| 2 |
import sys
|
| 3 |
import os
|
| 4 |
-
import io
|
| 5 |
from PyQt5 import QtWidgets, Qt, QtGui, QtCore, uic
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
from NewGenome import NewGenome
|
| 10 |
-
from NewEndonuclease import NewEndonuclease
|
| 11 |
-
import genomeBrowser
|
| 12 |
-
import webbrowser
|
| 13 |
-
import requests
|
| 14 |
-
import GlobalSettings
|
| 15 |
-
import multitargeting
|
| 16 |
-
from AnnotationParser import Annotation_Parser
|
| 17 |
-
from export_tool import export_tool
|
| 18 |
-
from generateLib import genLibrary
|
| 19 |
-
from CSPRparser import CSPRparser
|
| 20 |
-
import populationAnalysis
|
| 21 |
import platform
|
| 22 |
-
import ncbi
|
| 23 |
-
import glob
|
| 24 |
-
import traceback
|
| 25 |
-
import math
|
| 26 |
import logging
|
| 27 |
-
from
|
| 28 |
-
from
|
| 29 |
-
from
|
| 30 |
-
from
|
| 31 |
|
| 32 |
-
#logger alias for global logger
|
| 33 |
logger = GlobalSettings.logger
|
| 34 |
|
| 35 |
fontSize = 12
|
| 36 |
|
| 37 |
-
#Annotation file and search query from MainWindow
|
| 38 |
-
class AnnotationsWindow(QtWidgets.QMainWindow):
|
| 39 |
-
#init annotation window class
|
| 40 |
-
def __init__(self, info_path):
|
| 41 |
-
super(AnnotationsWindow, self).__init__()
|
| 42 |
-
uic.loadUi(GlobalSettings.appdir + 'annotation_details.ui', self)
|
| 43 |
-
self.setWindowIcon(Qt.QIcon(GlobalSettings.appdir + "cas9image.ico"))
|
| 44 |
-
self.Submit_button.clicked.connect(self.submit)
|
| 45 |
-
self.Go_Back_Button.clicked.connect(self.go_Back)
|
| 46 |
-
self.select_all_checkbox.stateChanged.connect(self.select_all_genes)
|
| 47 |
-
self.fontSize = 12 # Initialize fontSize
|
| 48 |
-
self.mainWindow = ""
|
| 49 |
-
self.type = ""
|
| 50 |
-
self.mwfg = self.frameGeometry() ##Center window
|
| 51 |
-
self.cp = QtWidgets.QDesktopWidget().availableGeometry().center() ##Center window
|
| 52 |
-
self.switcher_table = [1, 1, 1, 1, 1, 1, 1, 1]
|
| 53 |
-
self.tableWidget.setHorizontalScrollMode(QtWidgets.QAbstractItemView.ScrollPerPixel)
|
| 54 |
-
self.tableWidget.setVerticalScrollMode(QtWidgets.QAbstractItemView.ScrollPerPixel)
|
| 55 |
-
self.tableWidget.setSelectionMode(QtWidgets.QAbstractItemView.MultiSelection)
|
| 56 |
-
self.tableWidget.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
|
| 57 |
-
self.tableWidget.setAutoScroll(False)
|
| 58 |
-
self.tableWidget.horizontalHeader().sectionClicked.connect(self.table_sorting)
|
| 59 |
-
|
| 60 |
-
scale_ui(self)
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
def table_sorting(self, logicalIndex):
|
| 64 |
-
try:
|
| 65 |
-
self.switcher_table[logicalIndex] *= -1
|
| 66 |
-
order = QtCore.Qt.DescendingOrder if self.switcher_table[logicalIndex] == -1 else QtCore.Qt.AscendingOrder
|
| 67 |
-
self.tableWidget.sortItems(logicalIndex, order)
|
| 68 |
-
except Exception as e:
|
| 69 |
-
show_error("table_sorting() in Annotation Window", e)
|
| 70 |
-
|
| 71 |
-
#submit selected rows for results to process
|
| 72 |
-
def submit(self):
|
| 73 |
-
try:
|
| 74 |
-
self.mainWindow.collect_table_data_nonkegg()
|
| 75 |
-
self.mainWindow.show() # Open main window back up
|
| 76 |
-
except Exception as e:
|
| 77 |
-
logger.critical("Error in submit() in AnnotationsWindow.")
|
| 78 |
-
logger.critical(e)
|
| 79 |
-
logger.critical(traceback.format_exc())
|
| 80 |
-
show_error("submit() in AnnotationsWindow", e)
|
| 81 |
-
finally:
|
| 82 |
-
self.hide() # Close annotation window regardless of success or failure
|
| 83 |
-
|
| 84 |
-
#go back to main
|
| 85 |
-
def go_Back(self):
|
| 86 |
-
try:
|
| 87 |
-
self.tableWidget.clear()
|
| 88 |
-
self.mainWindow.searches.clear()
|
| 89 |
-
self.tableWidget.setColumnCount(0)
|
| 90 |
-
self.mainWindow.show()
|
| 91 |
-
self.mainWindow.progressBar.setValue(0)
|
| 92 |
-
self.hide()
|
| 93 |
-
except Exception as e:
|
| 94 |
-
show_error("go_Back() in AnnotationsWindow", e)
|
| 95 |
-
self.mainWindow.checkBoxes.clear()
|
| 96 |
-
|
| 97 |
-
# this is the connection for the select all checkbox - selects/deselects all the genes in the table
|
| 98 |
-
# this function is very similar to the other fill_table, it just works with the other types of annotation files
|
| 99 |
-
def fill_table_nonKegg(self, mainWindow, results_list):
|
| 100 |
-
try:
|
| 101 |
-
self.tableWidget.clearContents()
|
| 102 |
-
self.mainWindow = mainWindow
|
| 103 |
-
self.tableWidget.setColumnCount(5)
|
| 104 |
-
self.mainWindow.progressBar.setValue(85)
|
| 105 |
-
self.tableWidget.setHorizontalHeaderLabels(["Feature Type", "Chromosome/Scaffold #", "Feature ID/Locus Tag", "Feature Name", "Feature Description"])
|
| 106 |
-
|
| 107 |
-
mainWindow.checkBoxes = []
|
| 108 |
-
self.type = "nonkegg"
|
| 109 |
-
|
| 110 |
-
for index, result in enumerate(results_list[:1000]): # Limit to first 1000 results
|
| 111 |
-
self.tableWidget.setRowCount(index + 1) # Increment table row count
|
| 112 |
-
chrom, feature = result
|
| 113 |
-
|
| 114 |
-
# Create and set table items
|
| 115 |
-
items = [
|
| 116 |
-
QtWidgets.QTableWidgetItem(feature.type),
|
| 117 |
-
QtWidgets.QTableWidgetItem(str(chrom)),
|
| 118 |
-
QtWidgets.QTableWidgetItem(get_id(feature)),
|
| 119 |
-
QtWidgets.QTableWidgetItem(get_name(feature)),
|
| 120 |
-
QtWidgets.QTableWidgetItem(get_description(feature))
|
| 121 |
-
]
|
| 122 |
-
|
| 123 |
-
for col, item in enumerate(items):
|
| 124 |
-
self.tableWidget.setItem(index, col, item)
|
| 125 |
-
|
| 126 |
-
mainWindow.checkBoxes.append((chrom, feature, index))
|
| 127 |
-
|
| 128 |
-
self.tableWidget.resizeColumnsToContents()
|
| 129 |
-
mainWindow.hide()
|
| 130 |
-
|
| 131 |
-
#center on current screen
|
| 132 |
-
center_ui(self)
|
| 133 |
-
self.show()
|
| 134 |
-
self.activateWindow()
|
| 135 |
-
|
| 136 |
-
return 0
|
| 137 |
-
except Exception as e:
|
| 138 |
-
show_error("fill_table_nonKegg() in AnnotationsWindow", e)
|
| 139 |
-
|
| 140 |
-
# this is the connection for the select all checkbox - selects/deselects all the genes in the table
|
| 141 |
-
def select_all_genes(self):
|
| 142 |
-
try:
|
| 143 |
-
if self.select_all_checkbox.isChecked():
|
| 144 |
-
self.tableWidget.selectAll()
|
| 145 |
-
else:
|
| 146 |
-
self.tableWidget.clearSelection()
|
| 147 |
-
except Exception as e:
|
| 148 |
-
show_error("select_all_genes() in AnnotationsWindow", e)
|
| 149 |
-
|
| 150 |
-
# this function calls the closingWindow class.
|
| 151 |
-
def closeEvent(self, event):
|
| 152 |
-
try:
|
| 153 |
-
GlobalSettings.mainWindow.closeFunction()
|
| 154 |
-
except Exception as e:
|
| 155 |
-
show_error("closeEvent() in AnnotationsWindow", e)
|
| 156 |
-
event.accept()
|
| 157 |
-
|
| 158 |
-
# =========================================================================================
|
| 159 |
-
# CLASS NAME: CMainWindow
|
| 160 |
-
# Inputs: Takes in the path information from the startup window and also all input parameters
|
| 161 |
-
# Outputs: The results of the target search process by generating a new Results window
|
| 162 |
-
# =========================================================================================
|
| 163 |
-
class CMainWindow(QtWidgets.QMainWindow):
|
| 164 |
-
|
| 165 |
-
def __init__(self, info_path):
|
| 166 |
-
super(CMainWindow, self).__init__()
|
| 167 |
-
uic.loadUi(GlobalSettings.appdir + 'CASPER_main.ui', self)
|
| 168 |
-
self.dbpath = ""
|
| 169 |
-
self.inputstring = "" # This is the search string
|
| 170 |
-
self.info_path = info_path
|
| 171 |
-
self.anno_name = ""
|
| 172 |
-
self.endo_name = ""
|
| 173 |
-
self.fontSize = 12
|
| 174 |
-
self.org = ""
|
| 175 |
-
self.TNumbers = {} # the T numbers from a kegg search
|
| 176 |
-
self.orgcodes = {} # Stores the Kegg organism code by the format {full name : organism code}
|
| 177 |
-
self.gene_list = {} # list of genes (no ides what they pertain to
|
| 178 |
-
self.searches = {}
|
| 179 |
-
self.checkBoxes = []
|
| 180 |
-
self.genlib_list = [] # This list stores selected SeqFeatures from annotation window
|
| 181 |
-
self.checked_info = {}
|
| 182 |
-
self.check_ntseq_info = {} # the ntsequences that go along with the checked_info
|
| 183 |
-
self.annotation_parser = Annotation_Parser()
|
| 184 |
-
self.link_list = list() # the list of the downloadable links from the NCBI search
|
| 185 |
-
self.organismDict = dict() # the dictionary for the links to download. Key is the description of the organism, value is the ID that can be found in link_list
|
| 186 |
-
self.results_list = list()
|
| 187 |
-
self.organismData = list()
|
| 188 |
-
self.ncbi = ncbi.NCBI_search_tool()
|
| 189 |
-
|
| 190 |
-
groupbox_style = """
|
| 191 |
-
QGroupBox:title{subcontrol-origin: margin;
|
| 192 |
-
left: 10px;
|
| 193 |
-
padding: 0 5px 0 5px;}
|
| 194 |
-
QGroupBox#Step1{border: 2px solid rgb(111,181,110);
|
| 195 |
-
border-radius: 9px;
|
| 196 |
-
margin-top: 10px;
|
| 197 |
-
font: bold 14pt 'Arial';}
|
| 198 |
-
"""
|
| 199 |
-
|
| 200 |
-
self.Step1.setStyleSheet(groupbox_style)
|
| 201 |
-
self.Step2.setStyleSheet(groupbox_style.replace("Step1", "Step2"))
|
| 202 |
-
self.Step3.setStyleSheet(groupbox_style.replace("Step1", "Step3"))
|
| 203 |
-
self.CASPER_Navigation.setStyleSheet(groupbox_style.replace("Step1", "CASPER_Navigation").replace("solid","dashed").replace("rgb(111,181,110)","rgb(88,89,91)"))
|
| 204 |
-
|
| 205 |
-
self.setWindowIcon(Qt.QIcon(GlobalSettings.appdir + "cas9image.ico"))
|
| 206 |
-
self.pushButton_FindTargets.clicked.connect(self.gather_settings)
|
| 207 |
-
self.pushButton_ViewTargets.clicked.connect(self.view_results)
|
| 208 |
-
self.pushButton_ViewTargets.setEnabled(False)
|
| 209 |
-
self.GenerateLibrary.setEnabled(False)
|
| 210 |
-
self.radioButton_Gene.clicked.connect(self.toggle_annotation)
|
| 211 |
-
self.radioButton_Position.clicked.connect(self.toggle_annotation)
|
| 212 |
-
|
| 213 |
-
""" Connect functions to buttons """
|
| 214 |
-
self.newGenome_button.clicked.connect(self.launch_newGenome) # Connect launch function to New Genome
|
| 215 |
-
self.newEndo_button.clicked.connect(self.launch_newEndonuclease) # Connect launch function to New Endonuclease
|
| 216 |
-
self.multitargeting_button.clicked.connect(self.changeto_multitargeting) # Connect launch function to Multitargeting
|
| 217 |
-
self.populationAnalysis_button.clicked.connect(self.changeto_population_Analysis) # Connect launch function to PA
|
| 218 |
-
self.GenerateLibrary.clicked.connect(self.prep_genlib)
|
| 219 |
-
|
| 220 |
-
""" Connect functions to actions (menu bar) """
|
| 221 |
-
self.actionOpen_Genome_Browser.triggered.connect(self.launch_newGenomeBrowser)
|
| 222 |
-
self.actionExit.triggered.connect(self.close_app)
|
| 223 |
-
self.visit_repo.triggered.connect(self.visit_repo_func)
|
| 224 |
-
self.actionChange_Directory.triggered.connect(self.change_directory)
|
| 225 |
-
self.actionNCBI.triggered.connect(self.open_ncbi_web_page)
|
| 226 |
-
# self.actionCasper2.triggered.connect(self.open_casper2_web_page)
|
| 227 |
-
self.actionNCBI_BLAST.triggered.connect(self.open_ncbi_blast_web_page)
|
| 228 |
-
|
| 229 |
-
|
| 230 |
-
|
| 231 |
-
self.progressBar.setMinimum(0)
|
| 232 |
-
self.progressBar.setMaximum(100)
|
| 233 |
-
self.progressBar.reset()
|
| 234 |
-
self.Annotation_Window = AnnotationsWindow(info_path)
|
| 235 |
-
self.geneEntryField.setPlaceholderText("Example Inputs: \n\n"
|
| 236 |
-
"Option 1: Feature (ID, Locus Tag, or Name)\n"
|
| 237 |
-
"Example: 854068/YOL086C/ADH1 for S. cerevisiae alcohol dehydrogenase 1\n\n"
|
| 238 |
-
"Option 2: Position (chromosome,start,stop)\n"
|
| 239 |
-
"Example: 1,1,1000 for targeting chromosome 1, base pairs 1 to 1000\n\n"
|
| 240 |
-
"Option 3: Sequence (must be within the selected organism)\n"
|
| 241 |
-
"Example: Any nucleotide sequence between 100 and 10,000 base pairs.\n\n"
|
| 242 |
-
"*Note: to multiplex, separate multiple queries by new lines*\n"
|
| 243 |
-
"Example:\n"
|
| 244 |
-
"1,1,1000\n"
|
| 245 |
-
"5,1,500\n"
|
| 246 |
-
"etc.")
|
| 247 |
-
|
| 248 |
-
# show functionalities on window
|
| 249 |
-
self.newGenome = NewGenome(info_path)
|
| 250 |
-
self.newEndonuclease = NewEndonuclease()
|
| 251 |
-
self.CoTargeting = CoTargeting(info_path)
|
| 252 |
-
self.Results = Results()
|
| 253 |
-
self.export_tool_window = export_tool()
|
| 254 |
-
self.genLib = genLibrary()
|
| 255 |
-
self.myClosingWindow = closingWindow()
|
| 256 |
-
self.genomebrowser = genomeBrowser.genomebrowser()
|
| 257 |
-
self.launch_ncbi_button.clicked.connect(self.launch_ncbi)
|
| 258 |
-
|
| 259 |
-
#scale UI
|
| 260 |
-
self.first_show = True
|
| 261 |
-
scale_ui(self)
|
| 262 |
-
|
| 263 |
-
# this function prepares everything for the generate library function
|
| 264 |
-
# it is very similar to the gather settings, how ever it stores the data instead of calling the Annotation Window class
|
| 265 |
-
# it moves the data onto the generateLib function, and then opens that window
|
| 266 |
-
def prep_genlib(self):
|
| 267 |
-
# make sure the user actually inputs something
|
| 268 |
-
try:
|
| 269 |
-
inputstring = str(self.geneEntryField.toPlainText())
|
| 270 |
-
if (inputstring.startswith("Example Inputs:") or inputstring == ""):
|
| 271 |
-
msgBox = QtWidgets.QMessageBox()
|
| 272 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 273 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 274 |
-
msgBox.setWindowTitle("Error")
|
| 275 |
-
msgBox.setText("No gene has been entered. Please enter a gene.")
|
| 276 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Ok)
|
| 277 |
-
msgBox.exec()
|
| 278 |
-
|
| 279 |
-
else:
|
| 280 |
-
# standardize the input
|
| 281 |
-
inputstring = inputstring.lower()
|
| 282 |
-
found_matches_bool = True
|
| 283 |
-
# call the respective function
|
| 284 |
-
self.progressBar.setValue(10)
|
| 285 |
-
if self.radioButton_Gene.isChecked():
|
| 286 |
-
if len(self.genlib_list) > 0:
|
| 287 |
-
found_matches_bool = True
|
| 288 |
-
else:
|
| 289 |
-
found_matches_bool = False
|
| 290 |
-
elif self.radioButton_Position.isChecked() or self.radioButton_Sequence.isChecked():
|
| 291 |
-
msgBox = QtWidgets.QMessageBox()
|
| 292 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 293 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 294 |
-
msgBox.setWindowTitle("Error")
|
| 295 |
-
msgBox.setText("Generate Library can only work with feature searches.")
|
| 296 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Ok)
|
| 297 |
-
msgBox.exec()
|
| 298 |
-
|
| 299 |
-
return
|
| 300 |
-
"""
|
| 301 |
-
elif self.radioButton_Position.isChecked():
|
| 302 |
-
pinput = inputstring.split(';')
|
| 303 |
-
found_matches_bool = self.run_results("position", pinput,openAnnoWindow=False)
|
| 304 |
-
elif self.radioButton_Sequence.isChecked():
|
| 305 |
-
sinput = inputstring
|
| 306 |
-
found_matches_bool = self.run_results("sequence", sinput, openAnnoWindow=False)
|
| 307 |
-
"""
|
| 308 |
-
# if matches are found
|
| 309 |
-
if found_matches_bool == True:
|
| 310 |
-
# get the cspr file name
|
| 311 |
-
cspr_file = self.organisms_to_files[self.orgChoice.currentText()][self.endoChoice.currentText()][0]
|
| 312 |
-
if platform.system() == 'Windows':
|
| 313 |
-
cspr_file = GlobalSettings.CSPR_DB + '\\' + cspr_file
|
| 314 |
-
else:
|
| 315 |
-
cspr_file = GlobalSettings.CSPR_DB + '/' + cspr_file
|
| 316 |
-
kegg_non = 'non_kegg'
|
| 317 |
-
|
| 318 |
-
# launch generateLib
|
| 319 |
-
self.progressBar.setValue(100)
|
| 320 |
-
|
| 321 |
-
# calculate the total number of matches found
|
| 322 |
-
tempSum = len(self.genlib_list)
|
| 323 |
-
|
| 324 |
-
# warn the user if the number is greater than 50
|
| 325 |
-
if tempSum > 50:
|
| 326 |
-
msgBox = QtWidgets.QMessageBox()
|
| 327 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 328 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Question)
|
| 329 |
-
msgBox.setWindowTitle("Many Matches Found")
|
| 330 |
-
msgBox.setText("More than 50 matches have been found. Continuing could cause a slow down...\n\n Do you wish to continue?")
|
| 331 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Yes)
|
| 332 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.No)
|
| 333 |
-
msgBox.exec()
|
| 334 |
-
|
| 335 |
-
if (msgBox.result() == QtWidgets.QMessageBox.No):
|
| 336 |
-
self.searches.clear()
|
| 337 |
-
self.progressBar.setValue(0)
|
| 338 |
-
return -2
|
| 339 |
-
|
| 340 |
-
self.genLib.launch(self.genlib_list,cspr_file, kegg_non)
|
| 341 |
-
else:
|
| 342 |
-
self.progressBar.setValue(0)
|
| 343 |
-
except Exception as e:
|
| 344 |
-
logger.critical("Error in prep_genlib() in main.")
|
| 345 |
-
logger.critical(e)
|
| 346 |
-
logger.critical(traceback.format_exc())
|
| 347 |
-
|
| 348 |
-
#print("prep genlib")
|
| 349 |
-
msgBox = QtWidgets.QMessageBox()
|
| 350 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 351 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 352 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 353 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 354 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 355 |
-
msgBox.exec()
|
| 356 |
-
|
| 357 |
-
exit(-1)
|
| 358 |
-
|
| 359 |
-
# Function for collecting the settings from the input field and transferring them to run_results
|
| 360 |
-
def gather_settings(self):
|
| 361 |
-
try:
|
| 362 |
-
### If user searches multiple times for the same thing, this avoids re-searching the entire annotation file
|
| 363 |
-
check_org = self.orgChoice.currentText().lower()
|
| 364 |
-
check_endo = self.endoChoice.currentText().lower()
|
| 365 |
-
check_anno_name = self.annotation_files.currentText().lower()
|
| 366 |
-
check_input = str(self.geneEntryField.toPlainText()).lower()
|
| 367 |
-
if (check_input == self.inputstring and check_org == self.org and check_anno_name == self.anno_name and check_endo == self.endo_name):
|
| 368 |
-
same_search = True
|
| 369 |
-
else:
|
| 370 |
-
self.org = check_org
|
| 371 |
-
self.anno_name = check_anno_name
|
| 372 |
-
self.inputstring = check_input
|
| 373 |
-
self.endo_name = check_endo
|
| 374 |
-
same_search = False
|
| 375 |
-
|
| 376 |
-
# Error check: make sure the user actually inputs something
|
| 377 |
-
if (self.inputstring.startswith("Example Inputs:") or self.inputstring == ""):
|
| 378 |
-
msgBox = QtWidgets.QMessageBox()
|
| 379 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 380 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 381 |
-
msgBox.setWindowTitle("Error")
|
| 382 |
-
msgBox.setText(
|
| 383 |
-
"No feature has been searched for. Please enter a search.")
|
| 384 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Ok)
|
| 385 |
-
msgBox.exec()
|
| 386 |
-
|
| 387 |
-
else:
|
| 388 |
-
|
| 389 |
-
### Remove additional scoring columns if necessary
|
| 390 |
-
header = get_table_headers(self.Results.targetTable) # Returns headers of the target table in View Targets window
|
| 391 |
-
col_indices = [header.index(x) for x in GlobalSettings.algorithms if x in header] # Returns the index(es) of the alternative scoring column(s) in the target table of View Targets window
|
| 392 |
-
if len(col_indices) > 0: # If alternative scoring has been done
|
| 393 |
-
for i in col_indices:
|
| 394 |
-
self.Results.targetTable.removeColumn(i)
|
| 395 |
-
self.Results.targetTable.resizeColumnsToContents()
|
| 396 |
-
|
| 397 |
-
self.progressBar.setValue(10)
|
| 398 |
-
if self.radioButton_Gene.isChecked():
|
| 399 |
-
ginput = [x.strip() for x in self.inputstring.split('\n')] # Split search based on newline character and remove deadspace
|
| 400 |
-
self.run_results("feature", ginput, same_search)
|
| 401 |
-
elif self.radioButton_Position.isChecked():
|
| 402 |
-
pinput = [x.strip() for x in self.inputstring.split('\n')] # Split search based on newline character and remove deadspace
|
| 403 |
-
self.run_results("position", pinput, same_search)
|
| 404 |
-
elif self.radioButton_Sequence.isChecked():
|
| 405 |
-
sinput = self.inputstring
|
| 406 |
-
self.run_results("sequence", sinput, same_search)
|
| 407 |
-
except Exception as e:
|
| 408 |
-
logger.critical("Error in gather_settings() in main.")
|
| 409 |
-
logger.critical(e)
|
| 410 |
-
logger.critical(traceback.format_exc())
|
| 411 |
-
msgBox = QtWidgets.QMessageBox()
|
| 412 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 413 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 414 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 415 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 416 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 417 |
-
msgBox.exec()
|
| 418 |
-
msgBox = QtWidgets.QMessageBox()
|
| 419 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 420 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 421 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 422 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 423 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 424 |
-
msgBox.exec()
|
| 425 |
-
|
| 426 |
-
exit(-1)
|
| 427 |
-
|
| 428 |
-
# ---- Following functions are for running the auxillary algorithms and windows ---- #
|
| 429 |
-
# this function is parses the annotation file given, and then goes through and goes onto results
|
| 430 |
-
# it will call other versions of collect_table_data and fill_table that work with these file types
|
| 431 |
-
# this function should work with the any type of annotation file, besides kegg.
|
| 432 |
-
# this assumes that the parsers all store the data the same way, which gff and feature table do
|
| 433 |
-
# please make sure the genbank parser stores the data in the same way
|
| 434 |
-
# so far the gff files seems to all be different. Need to think about how we want to parse it
|
| 435 |
-
def run_results_own_ncbi_file(self, inputstring, fileName, same_search, openAnnoWindow=True):
|
| 436 |
-
try:
|
| 437 |
-
self.set_progress(35)
|
| 438 |
-
self.results_list = self.annotation_parser.genbank_search(inputstring, same_search)
|
| 439 |
-
|
| 440 |
-
cspr_file = self.organisms_to_files[self.orgChoice.currentText()][self.endoChoice.currentText()][0]
|
| 441 |
-
cspr_file = os.path.join(GlobalSettings.CSPR_DB, cspr_file)
|
| 442 |
-
|
| 443 |
-
own_cspr_parser = CSPRparser(cspr_file)
|
| 444 |
-
own_cspr_parser.read_first_lines()
|
| 445 |
-
if len(own_cspr_parser.karystatsList) != self.annotation_parser.max_chrom:
|
| 446 |
-
show_message(
|
| 447 |
-
fontSize=12,
|
| 448 |
-
icon=QtWidgets.QMessageBox.Icon.Warning,
|
| 449 |
-
title="Warning:",
|
| 450 |
-
message="The number of chromosomes do not match. This could cause errors.",
|
| 451 |
-
button=QtWidgets.QMessageBox.StandardButton.Ok
|
| 452 |
-
)
|
| 453 |
-
self.set_progress(60)
|
| 454 |
-
|
| 455 |
-
self.searches.clear()
|
| 456 |
-
|
| 457 |
-
self.set_progress(75)
|
| 458 |
-
if not self.results_list:
|
| 459 |
-
show_message(
|
| 460 |
-
fontSize=12,
|
| 461 |
-
icon=QtWidgets.QMessageBox.Icon.Critical,
|
| 462 |
-
title="No Matches Found",
|
| 463 |
-
message="No matches found with that search, please try again.",
|
| 464 |
-
button=QtWidgets.QMessageBox.StandardButton.Ok
|
| 465 |
-
)
|
| 466 |
-
self.set_progress(0)
|
| 467 |
-
return False if not openAnnoWindow else None
|
| 468 |
-
|
| 469 |
-
self.set_progress(80)
|
| 470 |
-
|
| 471 |
-
return self.Annotation_Window.fill_table_nonKegg(self, self.results_list) if openAnnoWindow else True
|
| 472 |
-
except Exception as e:
|
| 473 |
-
show_error(f"Error in run_results_own_ncbi_file() in main.", e)
|
| 474 |
-
|
| 475 |
-
def set_progress(self, value):
|
| 476 |
-
self.progressBar.setValue(value)
|
| 477 |
-
|
| 478 |
-
def run_results(self, inputtype, inputstring, same_search, openAnnoWindow=True):
|
| 479 |
-
try:
|
| 480 |
-
file_name = self.annotation_files.currentText()
|
| 481 |
-
for file in glob.glob(GlobalSettings.CSPR_DB + "/**/*.gb*", recursive=True):
|
| 482 |
-
if file_name in file:
|
| 483 |
-
self.annotation_parser.annotationFileName = file
|
| 484 |
-
break
|
| 485 |
-
self.Results.annotation_path = self.annotation_parser.annotationFileName
|
| 486 |
-
|
| 487 |
-
progvalue = 15
|
| 488 |
-
self.searches = {}
|
| 489 |
-
self.gene_list = {}
|
| 490 |
-
self.progressBar.setValue(progvalue)
|
| 491 |
-
|
| 492 |
-
try:
|
| 493 |
-
self.Results.endonucleaseBox.currentIndexChanged.disconnect()
|
| 494 |
-
except Exception as e:
|
| 495 |
-
pass
|
| 496 |
-
# set Results endo combo box
|
| 497 |
-
self.Results.endonucleaseBox.clear()
|
| 498 |
-
|
| 499 |
-
# set the results window endoChoice box menu
|
| 500 |
-
# set the mainWindow's endoChoice first, and then loop through and set the rest of them
|
| 501 |
-
self.Results.endonucleaseBox.addItem(self.endoChoice.currentText())
|
| 502 |
-
for item in self.organisms_to_endos[str(self.orgChoice.currentText())]:
|
| 503 |
-
if item != self.Results.endonucleaseBox.currentText():
|
| 504 |
-
self.Results.endonucleaseBox.addItem(item)
|
| 505 |
-
|
| 506 |
-
self.Results.endonucleaseBox.currentIndexChanged.connect(self.Results.changeEndonuclease)
|
| 507 |
-
self.Results.get_endo_data()
|
| 508 |
-
|
| 509 |
-
# self.Results.change_start_end_button.setEnabled(False)
|
| 510 |
-
self.Results.displayGeneViewer.setChecked(0)
|
| 511 |
-
|
| 512 |
-
if inputtype == "feature":
|
| 513 |
-
|
| 514 |
-
fileType = self.annotation_parser.find_which_file_version()
|
| 515 |
-
|
| 516 |
-
# if the parser retuns the 'wrong file type' error
|
| 517 |
-
if fileType == -1:
|
| 518 |
-
msgBox = QtWidgets.QMessageBox()
|
| 519 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 520 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 521 |
-
msgBox.setWindowTitle("Error:")
|
| 522 |
-
msgBox.setText("Feature search requires a GenBank formatted annotation file. Please select a file from the dropdown menu or search by position")
|
| 523 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Ok)
|
| 524 |
-
msgBox.exec()
|
| 525 |
-
|
| 526 |
-
self.progressBar.setValue(0)
|
| 527 |
-
return
|
| 528 |
-
|
| 529 |
-
# make sure an annotation file has been selected
|
| 530 |
-
if self.annotation_files.currentText() == "None":
|
| 531 |
-
msgBox = QtWidgets.QMessageBox()
|
| 532 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 533 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 534 |
-
msgBox.setWindowTitle("No Annotation")
|
| 535 |
-
msgBox.setText("Search by feature requires a GenBank annotation file. Please select one from the dropdown menu or search by position.")
|
| 536 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Ok)
|
| 537 |
-
msgBox.exec()
|
| 538 |
-
|
| 539 |
-
self.progressBar.setValue(0)
|
| 540 |
-
return
|
| 541 |
-
# this now just goes onto the other version of run_results
|
| 542 |
-
myBool = self.run_results_own_ncbi_file(inputstring, self.annotation_files.currentText(), same_search, openAnnoWindow=openAnnoWindow)
|
| 543 |
-
if not openAnnoWindow:
|
| 544 |
-
return myBool
|
| 545 |
-
else:
|
| 546 |
-
self.progressBar.setValue(0)
|
| 547 |
-
return
|
| 548 |
-
|
| 549 |
-
# position code below
|
| 550 |
-
if inputtype == "position":
|
| 551 |
-
full_org = str(self.orgChoice.currentText())
|
| 552 |
-
self.checked_info.clear()
|
| 553 |
-
self.check_ntseq_info.clear()
|
| 554 |
-
|
| 555 |
-
for item in inputstring: # Loop through each search
|
| 556 |
-
searchIndices = [x.strip() for x in item.split(',')] # Parse input query
|
| 557 |
-
### Make sure the right amount of arguments were passed
|
| 558 |
-
if len(searchIndices) != 3:
|
| 559 |
-
msgBox = QtWidgets.QMessageBox()
|
| 560 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 561 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 562 |
-
msgBox.setWindowTitle("Position Error: Invalid Input")
|
| 563 |
-
msgBox.setText(
|
| 564 |
-
"There are 3 arguments required for this function: chromosome, start position, and end position.")
|
| 565 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Ok)
|
| 566 |
-
msgBox.exec()
|
| 567 |
-
|
| 568 |
-
self.progressBar.setValue(0)
|
| 569 |
-
return
|
| 570 |
-
|
| 571 |
-
### Make sure user inputs digits
|
| 572 |
-
if not searchIndices[0].isdigit() or not searchIndices[1].isdigit() or not searchIndices[2].isdigit():
|
| 573 |
-
msgBox = QtWidgets.QMessageBox()
|
| 574 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 575 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 576 |
-
msgBox.setWindowTitle("Position Error: Invalid Input")
|
| 577 |
-
msgBox.setText(
|
| 578 |
-
"The positions given must be integers. Please try again.")
|
| 579 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Ok)
|
| 580 |
-
msgBox.exec()
|
| 581 |
-
|
| 582 |
-
self.progressBar.setValue(0)
|
| 583 |
-
return
|
| 584 |
-
|
| 585 |
-
### Make sure start is less than end
|
| 586 |
-
elif int(searchIndices[1]) >= int(searchIndices[2]):
|
| 587 |
-
msgBox = QtWidgets.QMessageBox()
|
| 588 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 589 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 590 |
-
msgBox.setWindowTitle("Position Error: Start Must Be Less Than End")
|
| 591 |
-
msgBox.setText(
|
| 592 |
-
"The start index must be less than the end index.")
|
| 593 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Ok)
|
| 594 |
-
msgBox.exec()
|
| 595 |
-
|
| 596 |
-
self.progressBar.setValue(0)
|
| 597 |
-
return
|
| 598 |
-
|
| 599 |
-
### Make sure range isn't too large
|
| 600 |
-
elif abs(int(searchIndices[2])-int(searchIndices[1])) > 50000:
|
| 601 |
-
msgBox = QtWidgets.QMessageBox()
|
| 602 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 603 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 604 |
-
msgBox.setWindowTitle("Position Error: Range Too Large")
|
| 605 |
-
msgBox.setText(
|
| 606 |
-
"The search range must be less than 50,000 nt.")
|
| 607 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Ok)
|
| 608 |
-
msgBox.exec()
|
| 609 |
-
|
| 610 |
-
self.progressBar.setValue(0)
|
| 611 |
-
return
|
| 612 |
-
|
| 613 |
-
### Make sure chromosome exists
|
| 614 |
-
elif int(searchIndices[0]) > self.annotation_parser.get_max_chrom():
|
| 615 |
-
msgBox = QtWidgets.QMessageBox()
|
| 616 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 617 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 618 |
-
msgBox.setWindowTitle("Position Error: Chromsome Doesn't Exist")
|
| 619 |
-
msgBox.setText(
|
| 620 |
-
"Chromosome %s does not exist in the selected annotation file." % searchIndices[0])
|
| 621 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Ok)
|
| 622 |
-
msgBox.exec()
|
| 623 |
-
|
| 624 |
-
self.progressBar.setValue(0)
|
| 625 |
-
return
|
| 626 |
-
|
| 627 |
-
# append the data into the checked_info
|
| 628 |
-
tempString = 'chrom: ' + str(searchIndices[0]) + ',start: ' + str(searchIndices[1]) + ',end: ' + str(searchIndices[2])
|
| 629 |
-
self.checked_info[tempString] = (int(searchIndices[0]), int(searchIndices[1])-1, int(searchIndices[2]))
|
| 630 |
-
|
| 631 |
-
self.progressBar.setValue(50)
|
| 632 |
-
self.Results.transfer_data(full_org, self.organisms_to_files[full_org], [str(self.endoChoice.currentText())], os.getcwd(), self.checked_info, self.check_ntseq_info,inputtype)
|
| 633 |
-
self.Results.load_gene_viewer()
|
| 634 |
-
self.progressBar.setValue(100)
|
| 635 |
-
self.pushButton_ViewTargets.setEnabled(True)
|
| 636 |
-
self.GenerateLibrary.setEnabled(True)
|
| 637 |
-
|
| 638 |
-
# sequence code below
|
| 639 |
-
if inputtype == "sequence":
|
| 640 |
-
fileType = self.annotation_parser.find_which_file_version()
|
| 641 |
-
# if the parser retuns the 'wrong file type' error
|
| 642 |
-
if fileType == -1:
|
| 643 |
-
msgBox = QtWidgets.QMessageBox()
|
| 644 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 645 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 646 |
-
msgBox.setWindowTitle("Error:")
|
| 647 |
-
msgBox.setText("Search by sequence requires a GenBank annotation file. Please select one from the dropdown menu or search by position.")
|
| 648 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Ok)
|
| 649 |
-
msgBox.exec()
|
| 650 |
-
|
| 651 |
-
self.progressBar.setValue(0)
|
| 652 |
-
return
|
| 653 |
-
if self.annotation_files.currentText() == "None":
|
| 654 |
-
msgBox = QtWidgets.QMessageBox()
|
| 655 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 656 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 657 |
-
msgBox.setWindowTitle("Error:")
|
| 658 |
-
msgBox.setText("Search by sequence requires a GenBank annotation file. Please select one from the dropdown menu or search by position.")
|
| 659 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Ok)
|
| 660 |
-
msgBox.exec()
|
| 661 |
-
|
| 662 |
-
self.progressBar.setValue(0)
|
| 663 |
-
return
|
| 664 |
-
|
| 665 |
-
|
| 666 |
-
checkString = 'AGTCN'
|
| 667 |
-
full_org = str(self.orgChoice.currentText())
|
| 668 |
-
self.checked_info.clear()
|
| 669 |
-
self.progressBar.setValue(10)
|
| 670 |
-
inputstring = inputstring.replace('\n','').upper().strip()
|
| 671 |
-
|
| 672 |
-
# make sure all the chars are one of A, G, T, C, or N
|
| 673 |
-
for letter in inputstring:
|
| 674 |
-
if letter not in checkString:
|
| 675 |
-
msgBox = QtWidgets.QMessageBox()
|
| 676 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 677 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 678 |
-
msgBox.setWindowTitle("Sequence Error")
|
| 679 |
-
msgBox.setText(
|
| 680 |
-
"The sequence must consist of A, G, T, C, or N. No other characters are allowed.")
|
| 681 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Ok)
|
| 682 |
-
msgBox.exec()
|
| 683 |
-
|
| 684 |
-
self.progressBar.setValue(0)
|
| 685 |
-
return
|
| 686 |
-
|
| 687 |
-
# check to make sure that the use gave a long enough sequence
|
| 688 |
-
if len(inputstring) < 100:
|
| 689 |
-
msgBox = QtWidgets.QMessageBox()
|
| 690 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 691 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 692 |
-
msgBox.setWindowTitle("Error")
|
| 693 |
-
msgBox.setText(
|
| 694 |
-
"The sequence given is too small. At least 100 characters are required.")
|
| 695 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Ok)
|
| 696 |
-
msgBox.exec()
|
| 697 |
-
|
| 698 |
-
self.progressBar.setValue(0)
|
| 699 |
-
return
|
| 700 |
-
|
| 701 |
-
# give a warning if the length of the sequence is long
|
| 702 |
-
if len(inputstring) > 10000:
|
| 703 |
-
msgBox = QtWidgets.QMessageBox()
|
| 704 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 705 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Question)
|
| 706 |
-
msgBox.setWindowTitle("Large Sequence Detected")
|
| 707 |
-
msgBox.setText(
|
| 708 |
-
"The sequence given is too large one.\n\nPlease input a sequence less than 10kb in length.")
|
| 709 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Yes)
|
| 710 |
-
msgBox.exec()
|
| 711 |
-
|
| 712 |
-
self.progressBar.setValue(0)
|
| 713 |
-
return
|
| 714 |
-
|
| 715 |
-
self.progressBar.setValue(30)
|
| 716 |
-
|
| 717 |
-
# Check the GBFF file for the sequence
|
| 718 |
-
my_check = self.annotation_parser.get_sequence_info(inputstring)
|
| 719 |
-
|
| 720 |
-
self.progressBar.setValue(55) # Update progress bar
|
| 721 |
-
|
| 722 |
-
if type(my_check) == bool: # This means the sequence was not found
|
| 723 |
-
msgBox = QtWidgets.QMessageBox()
|
| 724 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 725 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Question)
|
| 726 |
-
msgBox.setWindowTitle("Sequence Not Found")
|
| 727 |
-
msgBox.setText(
|
| 728 |
-
"The sequence entered was not found.\n\nPlease input a sequence that is in the selected organism.")
|
| 729 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Yes)
|
| 730 |
-
msgBox.exec()
|
| 731 |
-
self.progressBar.setValue(0)
|
| 732 |
-
return
|
| 733 |
-
|
| 734 |
-
else: # This means the sequence was found
|
| 735 |
-
# append the data into the checked_info
|
| 736 |
-
tempString = 'chrom: ' + str(my_check[0]) + ',start: ' + str(my_check[1]) + ',end: ' + str(my_check[2])
|
| 737 |
-
self.checked_info[tempString] = (int(my_check[0]), int(my_check[1])-1, int(my_check[2]))
|
| 738 |
-
|
| 739 |
-
self.progressBar.setValue(75) # Update progress bar
|
| 740 |
-
|
| 741 |
-
self.Results.transfer_data(full_org, self.organisms_to_files[full_org], [str(self.endoChoice.currentText())], os.getcwd(), self.checked_info, self.check_ntseq_info, inputtype)
|
| 742 |
-
self.Results.load_gene_viewer()
|
| 743 |
-
self.progressBar.setValue(100)
|
| 744 |
-
self.pushButton_ViewTargets.setEnabled(True)
|
| 745 |
-
self.GenerateLibrary.setEnabled(True)
|
| 746 |
-
|
| 747 |
-
|
| 748 |
-
except Exception as e:
|
| 749 |
-
logger.critical("Error in run_results() in main.")
|
| 750 |
-
logger.critical(e)
|
| 751 |
-
logger.critical(traceback.format_exc())
|
| 752 |
-
msgBox = QtWidgets.QMessageBox()
|
| 753 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 754 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 755 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 756 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 757 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 758 |
-
msgBox.exec()
|
| 759 |
-
|
| 760 |
-
exit(-1)
|
| 761 |
-
|
| 762 |
-
def handle_feature_search(self, input_string, open_anno_window):
|
| 763 |
-
file_type = self.annotation_parser.find_which_file_version()
|
| 764 |
-
if file_type == -1 or self.annotation_files.currentText() == "None":
|
| 765 |
-
self.show_error_message("Feature search requires a GenBank formatted annotation file.")
|
| 766 |
-
return False
|
| 767 |
-
|
| 768 |
-
return self.run_results_own_ncbi_file(input_string, self.annotation_files.currentText(), same_search, open_anno_window)
|
| 769 |
-
|
| 770 |
-
|
| 771 |
-
def launch_newGenome(self):
|
| 772 |
-
try:
|
| 773 |
-
# Update endo list
|
| 774 |
-
self.newGenome.fillEndo()
|
| 775 |
-
if self.newGenome.first_show:
|
| 776 |
-
center_ui(self.newGenome)
|
| 777 |
-
self.newGenome.first_show = False
|
| 778 |
-
self.hide()
|
| 779 |
-
self.newGenome.show()
|
| 780 |
-
except Exception as e:
|
| 781 |
-
show_error("launch_newGenome() in main", e)
|
| 782 |
-
|
| 783 |
-
#launch new endo tool
|
| 784 |
-
def launch_newEndonuclease(self):
|
| 785 |
-
try:
|
| 786 |
-
# Initialize and display the new endonuclease window
|
| 787 |
-
self.newEndonuclease.centerUI()
|
| 788 |
-
self.newEndonuclease.show()
|
| 789 |
-
self.newEndonuclease.activateWindow()
|
| 790 |
-
except Exception as e:
|
| 791 |
-
show_error("launch_newEndonuclease() in main", e)
|
| 792 |
-
|
| 793 |
-
#launch genome browser tool
|
| 794 |
-
def launch_newGenomeBrowser(self):
|
| 795 |
-
try:
|
| 796 |
-
self.genomebrowser.createGraph(self)
|
| 797 |
-
except Exception as e:
|
| 798 |
-
show_error("launch_newGenomeBrowser() in main", e)
|
| 799 |
-
|
| 800 |
-
#launch ncbi tool
|
| 801 |
-
def launch_ncbi(self):
|
| 802 |
-
try:
|
| 803 |
-
msgBox = QtWidgets.QMessageBox()
|
| 804 |
-
msgBox.setStyleSheet(f"font: {self.fontSize}pt 'Arial'")
|
| 805 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Information)
|
| 806 |
-
msgBox.setWindowTitle("Note:")
|
| 807 |
-
msgBox.setText(
|
| 808 |
-
"NCBI Annotation Guidelines:\n\nDownload annotation files of the exact species and strain used in Analyze New Genome.\n\nMismatched annotation files will inhibit downstream analyses.")
|
| 809 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Ok)
|
| 810 |
-
msgBox.exec()
|
| 811 |
-
|
| 812 |
-
if self.ncbi.first_show:
|
| 813 |
-
self.ncbi.first_show = False
|
| 814 |
-
self.ncbi.centerUI()
|
| 815 |
-
|
| 816 |
-
self.ncbi.show()
|
| 817 |
-
self.ncbi.activateWindow()
|
| 818 |
-
except Exception as e:
|
| 819 |
-
show_error("launch_ncbi() in main", e)
|
| 820 |
-
|
| 821 |
-
# this function does the same stuff that the other collect_table_data does, but works with the other types of files
|
| 822 |
-
def collect_table_data_nonkegg(self):
|
| 823 |
-
try:
|
| 824 |
-
# start out the same as the other collect_table_data
|
| 825 |
-
self.checked_info.clear()
|
| 826 |
-
self.genlib_list.clear()
|
| 827 |
-
self.check_ntseq_info.clear()
|
| 828 |
-
full_org = str(self.orgChoice.currentText())
|
| 829 |
-
holder = ()
|
| 830 |
-
selected_indices = []
|
| 831 |
-
selected_rows = self.Annotation_Window.tableWidget.selectionModel().selectedRows()
|
| 832 |
-
for ind in sorted(selected_rows):
|
| 833 |
-
selected_indices.append(ind.row())
|
| 834 |
-
|
| 835 |
-
for item in self.checkBoxes:
|
| 836 |
-
feature = item[1]
|
| 837 |
-
# If inidices of checkBoxes list and selected rows in table match...
|
| 838 |
-
if item[2] in selected_indices:
|
| 839 |
-
holder = (item[0],int(feature.location.start),int(feature.location.end)) # Tuple order: Feature chromosome/scaffold number, feature start, feature end
|
| 840 |
-
### If locus tag available, combine with gene name to create dict key
|
| 841 |
-
if 'locus_tag' in feature.qualifiers:
|
| 842 |
-
tag = feature.qualifiers['locus_tag'][0]
|
| 843 |
-
key = tag + ": " + get_name(feature)
|
| 844 |
-
else:
|
| 845 |
-
key = get_name(feature)
|
| 846 |
-
self.checked_info[key] = holder
|
| 847 |
-
self.genlib_list.append((item[0],feature)) # Tuple order: Feature chromosome/scaffold number, SeqFeature object
|
| 848 |
-
else:
|
| 849 |
-
# If item was not selected in the table, go to the next item
|
| 850 |
-
continue
|
| 851 |
-
|
| 852 |
-
# now call transfer data
|
| 853 |
-
self.progressBar.setValue(95)
|
| 854 |
-
self.Results.transfer_data(full_org, self.organisms_to_files[full_org], [str(self.endoChoice.currentText())], os.getcwd(),
|
| 855 |
-
self.checked_info, self.check_ntseq_info,inputtype="feature")
|
| 856 |
-
self.Results.load_gene_viewer()
|
| 857 |
-
|
| 858 |
-
self.progressBar.setValue(100)
|
| 859 |
-
self.pushButton_ViewTargets.setEnabled(True)
|
| 860 |
-
self.GenerateLibrary.setEnabled(True)
|
| 861 |
-
except Exception as e:
|
| 862 |
-
logger.critical("Error in collect_table_data_nonkegg() in main.")
|
| 863 |
-
logger.critical(e)
|
| 864 |
-
logger.critical(traceback.format_exc())
|
| 865 |
-
msgBox = QtWidgets.QMessageBox()
|
| 866 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 867 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 868 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 869 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 870 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 871 |
-
msgBox.exec()
|
| 872 |
-
|
| 873 |
-
exit(-1)
|
| 874 |
-
|
| 875 |
-
def separate_line(self, input_string):
|
| 876 |
-
try:
|
| 877 |
-
export_array = []
|
| 878 |
-
while True:
|
| 879 |
-
index = input_string.find('\n')
|
| 880 |
-
if index == -1:
|
| 881 |
-
if len(input_string) == 0:
|
| 882 |
-
return export_array
|
| 883 |
-
else:
|
| 884 |
-
export_array.append(input_string)
|
| 885 |
-
return export_array
|
| 886 |
-
export_array.append(input_string[:index])
|
| 887 |
-
input_string = input_string[index + 1:]
|
| 888 |
-
except Exception as e:
|
| 889 |
-
logger.critical("Error in seperate_line() in main.")
|
| 890 |
-
logger.critical(e)
|
| 891 |
-
logger.critical(traceback.format_exc())
|
| 892 |
-
msgBox = QtWidgets.QMessageBox()
|
| 893 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 894 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 895 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 896 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 897 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 898 |
-
msgBox.exec()
|
| 899 |
-
|
| 900 |
-
exit(-1)
|
| 901 |
-
|
| 902 |
-
def removeWhiteSpace(self, strng):
|
| 903 |
-
try:
|
| 904 |
-
while True:
|
| 905 |
-
if len(strng) == 0 or (strng[0] != " " and strng[0] != "\n"):
|
| 906 |
-
break
|
| 907 |
-
strng = strng[1:]
|
| 908 |
-
while True:
|
| 909 |
-
if len(strng) == 0 or (strng[len(strng) - 1] != " " and strng[0] != "\n"):
|
| 910 |
-
return strng
|
| 911 |
-
strng = strng[:len(strng) - 1]
|
| 912 |
-
except Exception as e:
|
| 913 |
-
logger.critical("Error in removeWhiteSpace() in main.")
|
| 914 |
-
logger.critical(e)
|
| 915 |
-
logger.critical(traceback.format_exc())
|
| 916 |
-
msgBox = QtWidgets.QMessageBox()
|
| 917 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 918 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 919 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 920 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 921 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 922 |
-
msgBox.exec()
|
| 923 |
-
|
| 924 |
-
exit(-1)
|
| 925 |
-
|
| 926 |
-
# Function to enable and disable the Annotation function if searching by position or sequence
|
| 927 |
-
def toggle_annotation(self):
|
| 928 |
-
try:
|
| 929 |
-
if self.radioButton_Gene.isChecked():
|
| 930 |
-
self.Step2.setEnabled(True)
|
| 931 |
-
else:
|
| 932 |
-
self.Step2.setEnabled(True)
|
| 933 |
-
except Exception as e:
|
| 934 |
-
logger.critical("Error in toggle_annotation() in main.")
|
| 935 |
-
logger.critical(e)
|
| 936 |
-
logger.critical(traceback.format_exc())
|
| 937 |
-
msgBox = QtWidgets.QMessageBox()
|
| 938 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 939 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 940 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 941 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 942 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 943 |
-
msgBox.exec()
|
| 944 |
-
|
| 945 |
-
exit(-1)
|
| 946 |
-
|
| 947 |
-
def fill_annotation_dropdown(self):
|
| 948 |
-
try:
|
| 949 |
-
#recursive search for all GenBank files in casper db folder
|
| 950 |
-
self.annotation_files.clear()
|
| 951 |
-
annotation_files = glob.glob(GlobalSettings.CSPR_DB + "/**/*.gb*", recursive=True)
|
| 952 |
-
if platform.system() == "Windows":
|
| 953 |
-
for i in range(len(annotation_files)):
|
| 954 |
-
annotation_files[i] = annotation_files[i].replace("/","\\")
|
| 955 |
-
annotation_files[i] = annotation_files[i][annotation_files[i].rfind("\\") + 1:]
|
| 956 |
-
else:
|
| 957 |
-
for i in range(len(annotation_files)):
|
| 958 |
-
annotation_files[i] = annotation_files[i].replace("\\","/")
|
| 959 |
-
annotation_files[i] = annotation_files[i][annotation_files[i].rfind("/") + 1:]
|
| 960 |
-
|
| 961 |
-
annotation_files.sort(key=str.lower)
|
| 962 |
-
self.annotation_files.addItems(annotation_files)
|
| 963 |
-
self.annotation_files.addItems(["None"])
|
| 964 |
-
except Exception as e:
|
| 965 |
-
logger.critical("Error in fill_annotation_dropdown() in main.")
|
| 966 |
-
logger.critical(e)
|
| 967 |
-
logger.critical(traceback.format_exc())
|
| 968 |
-
msgBox = QtWidgets.QMessageBox()
|
| 969 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 970 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 971 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 972 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 973 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 974 |
-
msgBox.exec()
|
| 975 |
-
|
| 976 |
-
exit(-1)
|
| 977 |
-
|
| 978 |
-
def make_dictonary(self):
|
| 979 |
-
try:
|
| 980 |
-
url = "https://www.genome.jp/dbget-bin/get_linkdb?-t+genes+gn:" + self.TNumbers[
|
| 981 |
-
self.Annotations_Organism.currentText()]
|
| 982 |
-
source_code = requests.get(url, verify=False)
|
| 983 |
-
plain_text = source_code.text
|
| 984 |
-
buf = io.StringIO(plain_text)
|
| 985 |
-
|
| 986 |
-
while True:
|
| 987 |
-
line = buf.readline()
|
| 988 |
-
if line[0] == "-":
|
| 989 |
-
break
|
| 990 |
-
while True:
|
| 991 |
-
line = buf.readline()
|
| 992 |
-
if line[1] != "a":
|
| 993 |
-
return
|
| 994 |
-
line = line[line.find(">") + 1:]
|
| 995 |
-
seq = line[line.find(":") + 1:line.find("<")]
|
| 996 |
-
line = line[line.find(">") + 1:]
|
| 997 |
-
|
| 998 |
-
i = 0
|
| 999 |
-
while True:
|
| 1000 |
-
if line[i] == " ":
|
| 1001 |
-
i = i + 1
|
| 1002 |
-
else:
|
| 1003 |
-
break
|
| 1004 |
-
key = line[i:line.find("\n") - 1]
|
| 1005 |
-
if key in self.gene_list:
|
| 1006 |
-
if seq not in self.gene_list[key]:
|
| 1007 |
-
self.gene_list[key].append(seq)
|
| 1008 |
-
else:
|
| 1009 |
-
self.gene_list[key] = [seq]
|
| 1010 |
-
z = 5
|
| 1011 |
-
except Exception as e:
|
| 1012 |
-
logger.critical("Error in make_dictionary() in main.")
|
| 1013 |
-
logger.critical(e)
|
| 1014 |
-
logger.critical(traceback.format_exc())
|
| 1015 |
-
msgBox = QtWidgets.QMessageBox()
|
| 1016 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 1017 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 1018 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 1019 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 1020 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 1021 |
-
msgBox.exec()
|
| 1022 |
-
|
| 1023 |
-
exit(-1)
|
| 1024 |
-
|
| 1025 |
-
def organism_finder(self, long_str):
|
| 1026 |
-
try:
|
| 1027 |
-
semi = long_str.find(";")
|
| 1028 |
-
index = 1
|
| 1029 |
-
while True:
|
| 1030 |
-
if long_str[semi - index] == " ":
|
| 1031 |
-
break
|
| 1032 |
-
index = index + 1
|
| 1033 |
-
return long_str[:semi - index]
|
| 1034 |
-
except Exception as e:
|
| 1035 |
-
logger.critical("Error trying in organism_finder() in main.")
|
| 1036 |
-
logger.critical(e)
|
| 1037 |
-
logger.critical(traceback.format_exc())
|
| 1038 |
-
msgBox = QtWidgets.QMessageBox()
|
| 1039 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 1040 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 1041 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 1042 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 1043 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 1044 |
-
msgBox.exec()
|
| 1045 |
-
|
| 1046 |
-
exit(-1)
|
| 1047 |
-
|
| 1048 |
-
# This method is for testing the execution of a button call to make sure the button is linked properly
|
| 1049 |
-
def testexe(self):
|
| 1050 |
-
try:
|
| 1051 |
-
msgBox = QtWidgets.QMessageBox()
|
| 1052 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 1053 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Question)
|
| 1054 |
-
msgBox.setWindowTitle("Extract!")
|
| 1055 |
-
msgBox.setText(
|
| 1056 |
-
"Are you sure you want to quit?")
|
| 1057 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Yes)
|
| 1058 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.No)
|
| 1059 |
-
msgBox.exec()
|
| 1060 |
-
|
| 1061 |
-
if msgBox.result() == QtWidgets.QMessageBox.Yes:
|
| 1062 |
-
# print(self.orgChoice.currentText())
|
| 1063 |
-
sys.exit()
|
| 1064 |
-
else:
|
| 1065 |
-
pass
|
| 1066 |
-
except Exception as e:
|
| 1067 |
-
logger.critical("Error in testexe() in main.")
|
| 1068 |
-
logger.critical(e)
|
| 1069 |
-
logger.critical(traceback.format_exc())
|
| 1070 |
-
msgBox = QtWidgets.QMessageBox()
|
| 1071 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 1072 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 1073 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 1074 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 1075 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 1076 |
-
msgBox.exec()
|
| 1077 |
-
|
| 1078 |
-
exit(-1)
|
| 1079 |
-
|
| 1080 |
-
def getData(self):
|
| 1081 |
-
try:
|
| 1082 |
-
try:
|
| 1083 |
-
self.orgChoice.currentIndexChanged.disconnect()
|
| 1084 |
-
except Exception as e:
|
| 1085 |
-
pass
|
| 1086 |
-
|
| 1087 |
-
self.orgChoice.clear()
|
| 1088 |
-
self.endoChoice.clear()
|
| 1089 |
-
mypath = os.getcwd()
|
| 1090 |
-
found = False
|
| 1091 |
-
self.dbpath = mypath
|
| 1092 |
-
onlyfiles = [str(f) for f in os.listdir(mypath) if os.path.isfile(os.path.join(mypath, f))]
|
| 1093 |
-
onlyfiles.sort(key=str.lower)
|
| 1094 |
-
self.organisms_to_files = {}
|
| 1095 |
-
self.organisms_to_endos = {}
|
| 1096 |
-
first = True
|
| 1097 |
-
for file in onlyfiles:
|
| 1098 |
-
if file.find('.cspr') != -1:
|
| 1099 |
-
if first == True:
|
| 1100 |
-
first = False
|
| 1101 |
-
found = True
|
| 1102 |
-
newname = file[0:-4]
|
| 1103 |
-
endo = newname[newname.rfind("_")+1:-1]
|
| 1104 |
-
hold = open(file, 'r')
|
| 1105 |
-
buf = (hold.readline())
|
| 1106 |
-
buf = str(buf)
|
| 1107 |
-
buf = buf.strip()
|
| 1108 |
-
species = buf.replace("GENOME: ",'')
|
| 1109 |
-
|
| 1110 |
-
if species in self.organisms_to_files:
|
| 1111 |
-
self.organisms_to_files[species][endo] = [file, file.replace(".cspr", "_repeats.db")]
|
| 1112 |
-
else:
|
| 1113 |
-
self.organisms_to_files[species] = {}
|
| 1114 |
-
self.organisms_to_files[species][endo] = [file, file.replace(".cspr", "_repeats.db")]
|
| 1115 |
-
|
| 1116 |
-
if species in self.organisms_to_endos:
|
| 1117 |
-
self.organisms_to_endos[species].append(endo)
|
| 1118 |
-
else:
|
| 1119 |
-
self.organisms_to_endos[species] = [endo]
|
| 1120 |
-
if self.orgChoice.findText(species) == -1:
|
| 1121 |
-
self.orgChoice.addItem(species)
|
| 1122 |
-
|
| 1123 |
-
#self.orgChoice.addItem("Custom Input Sequences")
|
| 1124 |
-
# auto fill the kegg search bar with the first choice in orgChoice
|
| 1125 |
-
if found == False:
|
| 1126 |
-
return False
|
| 1127 |
-
|
| 1128 |
-
self.endoChoice.clear()
|
| 1129 |
-
self.endoChoice.addItems(self.organisms_to_endos[str(self.orgChoice.currentText())])
|
| 1130 |
-
self.orgChoice.currentIndexChanged.connect(self.changeEndos)
|
| 1131 |
-
except Exception as e:
|
| 1132 |
-
logger.critical("Error in getData() in main.")
|
| 1133 |
-
logger.critical(e)
|
| 1134 |
-
logger.critical(traceback.format_exc())
|
| 1135 |
-
msgBox = QtWidgets.QMessageBox()
|
| 1136 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 1137 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 1138 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 1139 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 1140 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 1141 |
-
msgBox.exec()
|
| 1142 |
-
|
| 1143 |
-
exit(-1)
|
| 1144 |
-
|
| 1145 |
-
def changeEndos(self):
|
| 1146 |
-
try:
|
| 1147 |
-
if self.orgChoice.currentText() != "Custom Input Sequences":
|
| 1148 |
-
self.Step2.setEnabled(True)
|
| 1149 |
-
self.endoChoice.setEnabled(True)
|
| 1150 |
-
self.radioButton_Gene.show()
|
| 1151 |
-
self.radioButton_Position.show()
|
| 1152 |
-
self.endoChoice.clear()
|
| 1153 |
-
self.endoChoice.addItems(self.organisms_to_endos[str(self.orgChoice.currentText())])
|
| 1154 |
-
else:
|
| 1155 |
-
self.Step2.setEnabled(False)
|
| 1156 |
-
self.endoChoice.clear()
|
| 1157 |
-
self.endoChoice.setEnabled(False)
|
| 1158 |
-
self.radioButton_Gene.hide()
|
| 1159 |
-
self.radioButton_Position.hide()
|
| 1160 |
-
except Exception as e:
|
| 1161 |
-
logger.critical("Error in changeEndos() in main.")
|
| 1162 |
-
logger.critical(e)
|
| 1163 |
-
logger.critical(traceback.format_exc())
|
| 1164 |
-
msgBox = QtWidgets.QMessageBox()
|
| 1165 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 1166 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 1167 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 1168 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 1169 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 1170 |
-
msgBox.exec()
|
| 1171 |
-
|
| 1172 |
-
exit(-1)
|
| 1173 |
-
|
| 1174 |
-
def change_directory(self):
|
| 1175 |
-
try:
|
| 1176 |
-
mydir = QtWidgets.QFileDialog.getExistingDirectory(
|
| 1177 |
-
None, "Open a folder...", self.dbpath, QtWidgets.QFileDialog.ShowDirsOnly)
|
| 1178 |
-
|
| 1179 |
-
if not os.path.isdir(mydir):
|
| 1180 |
-
show_message(
|
| 1181 |
-
fontSize=12,
|
| 1182 |
-
icon=QtWidgets.QMessageBox.Icon.Critical,
|
| 1183 |
-
title="Not a directory",
|
| 1184 |
-
message="The directory you selected does not exist."
|
| 1185 |
-
)
|
| 1186 |
-
return
|
| 1187 |
-
|
| 1188 |
-
if not any(file.endswith(".cspr") for file in os.listdir(mydir)):
|
| 1189 |
-
show_message(
|
| 1190 |
-
fontSize=12,
|
| 1191 |
-
icon=QtWidgets.QMessageBox.Icon.Critical,
|
| 1192 |
-
title="Directory is invalid!",
|
| 1193 |
-
message="You must select a directory with CSPR Files!"
|
| 1194 |
-
)
|
| 1195 |
-
return
|
| 1196 |
-
|
| 1197 |
-
os.chdir(mydir)
|
| 1198 |
-
mydir = mydir.replace("/", "\\") if platform.system() == "Windows" else mydir
|
| 1199 |
-
GlobalSettings.CSPR_DB = mydir
|
| 1200 |
-
|
| 1201 |
-
GlobalSettings.MTWin.directory = mydir
|
| 1202 |
-
GlobalSettings.MTWin.get_data()
|
| 1203 |
-
GlobalSettings.pop_Analysis.get_data()
|
| 1204 |
-
self.getData()
|
| 1205 |
-
self.fill_annotation_dropdown()
|
| 1206 |
-
except Exception as e:
|
| 1207 |
-
show_error("Error in change_directory() in main.", e)
|
| 1208 |
-
|
| 1209 |
-
#change to multi-targeting window
|
| 1210 |
-
def changeto_multitargeting(self):
|
| 1211 |
-
try:
|
| 1212 |
-
os.chdir(os.getcwd())
|
| 1213 |
-
if GlobalSettings.MTWin.first_show == True:
|
| 1214 |
-
GlobalSettings.MTWin.show()
|
| 1215 |
-
GlobalSettings.MTWin.first_show = False
|
| 1216 |
-
else:
|
| 1217 |
-
GlobalSettings.MTWin.show()
|
| 1218 |
-
GlobalSettings.mainWindow.hide()
|
| 1219 |
-
|
| 1220 |
-
except Exception as e:
|
| 1221 |
-
logger.critical("Error in changeto_multitargeting() in main.")
|
| 1222 |
-
logger.critical(e)
|
| 1223 |
-
logger.critical(traceback.format_exc())
|
| 1224 |
-
msgBox = QtWidgets.QMessageBox()
|
| 1225 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 1226 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 1227 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 1228 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 1229 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 1230 |
-
msgBox.exec()
|
| 1231 |
-
|
| 1232 |
-
exit(-1)
|
| 1233 |
-
|
| 1234 |
-
#change to population analysis window
|
| 1235 |
-
def changeto_population_Analysis(self):
|
| 1236 |
-
try:
|
| 1237 |
-
GlobalSettings.pop_Analysis.launch()
|
| 1238 |
-
if GlobalSettings.pop_Analysis.first_show == True:
|
| 1239 |
-
GlobalSettings.pop_Analysis.centerUI()
|
| 1240 |
-
GlobalSettings.pop_Analysis.first_show = False
|
| 1241 |
-
GlobalSettings.pop_Analysis.show()
|
| 1242 |
-
GlobalSettings.mainWindow.hide()
|
| 1243 |
-
except Exception as e:
|
| 1244 |
-
logger.critical("Error in changeto_population_Analysis() in main.")
|
| 1245 |
-
logger.critical(e)
|
| 1246 |
-
logger.critical(traceback.format_exc())
|
| 1247 |
-
msgBox = QtWidgets.QMessageBox()
|
| 1248 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 1249 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 1250 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 1251 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 1252 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 1253 |
-
msgBox.exec()
|
| 1254 |
-
|
| 1255 |
-
exit(-1)
|
| 1256 |
-
|
| 1257 |
-
def annotation_information(self):
|
| 1258 |
-
try:
|
| 1259 |
-
info = "Annotation files are used for searching for spacers on a gene/locus basis and can be selected here using either " \
|
| 1260 |
-
"NCBI databases or a local file."
|
| 1261 |
-
msgBox = QtWidgets.QMessageBox()
|
| 1262 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 1263 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 1264 |
-
msgBox.setWindowTitle("Annotation Information")
|
| 1265 |
-
msgBox.setText(
|
| 1266 |
-
info)
|
| 1267 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Ok)
|
| 1268 |
-
msgBox.exec()
|
| 1269 |
-
|
| 1270 |
-
except Exception as e:
|
| 1271 |
-
logger.critical("Error in annotation_information() in main.")
|
| 1272 |
-
logger.critical(e)
|
| 1273 |
-
logger.critical(traceback.format_exc())
|
| 1274 |
-
msgBox = QtWidgets.QMessageBox()
|
| 1275 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 1276 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 1277 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 1278 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 1279 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 1280 |
-
msgBox.exec()
|
| 1281 |
-
|
| 1282 |
-
exit(-1)
|
| 1283 |
-
|
| 1284 |
-
def open_ncbi_blast_web_page(self):
|
| 1285 |
-
try:
|
| 1286 |
-
webbrowser.open('https://blast.ncbi.nlm.nih.gov/Blast.cgi', new=2)
|
| 1287 |
-
except Exception as e:
|
| 1288 |
-
show_error("open_ncbi_blast_web_page() in main", e)
|
| 1289 |
-
|
| 1290 |
-
def open_ncbi_web_page(self):
|
| 1291 |
-
try:
|
| 1292 |
-
webbrowser.open('https://www.ncbi.nlm.nih.gov/', new=2)
|
| 1293 |
-
except Exception as e:
|
| 1294 |
-
show_error("open_ncbi_web_page() in main", e)
|
| 1295 |
-
|
| 1296 |
-
# def open_casper2_web_page(self):
|
| 1297 |
-
# try:
|
| 1298 |
-
# webbrowser.open('http://casper2.org/', new=2)
|
| 1299 |
-
# except Exception as e:
|
| 1300 |
-
# logger.critical("Error in open_casper2_web_page() in main.")
|
| 1301 |
-
# logger.critical(e)
|
| 1302 |
-
# logger.critical(traceback.format_exc())
|
| 1303 |
-
# exit(-1)
|
| 1304 |
-
|
| 1305 |
-
def visit_repo_func(self):
|
| 1306 |
-
try:
|
| 1307 |
-
webbrowser.open('https://github.com/TrinhLab/CASPERapp')
|
| 1308 |
-
except Exception as e:
|
| 1309 |
-
show_error("visit_repo_func() in main", e)
|
| 1310 |
-
|
| 1311 |
-
@QtCore.pyqtSlot()
|
| 1312 |
-
def view_results(self):
|
| 1313 |
-
try:
|
| 1314 |
-
#center results window on current screen
|
| 1315 |
-
if self.Results.first_show == True:
|
| 1316 |
-
self.Results.first_show = False
|
| 1317 |
-
self.Results.centerUI()
|
| 1318 |
-
|
| 1319 |
-
self.Results.show()
|
| 1320 |
-
self.hide()
|
| 1321 |
-
except Exception as e:
|
| 1322 |
-
logger.critical("Error in view_results() in main.")
|
| 1323 |
-
logger.critical(e)
|
| 1324 |
-
logger.critical(traceback.format_exc())
|
| 1325 |
-
msgBox = QtWidgets.QMessageBox()
|
| 1326 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 1327 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 1328 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 1329 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 1330 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 1331 |
-
msgBox.exec()
|
| 1332 |
-
|
| 1333 |
-
exit(-1)
|
| 1334 |
-
|
| 1335 |
-
def closeFunction(self):
|
| 1336 |
-
try:
|
| 1337 |
-
# Attempt to close the NCBI window if it exists
|
| 1338 |
-
try:
|
| 1339 |
-
self.ncbi.close()
|
| 1340 |
-
except AttributeError:
|
| 1341 |
-
print("No NCBI window to close.")
|
| 1342 |
-
|
| 1343 |
-
# Proceed with closing operations
|
| 1344 |
-
self.myClosingWindow.get_files()
|
| 1345 |
-
self.myClosingWindow.centerUI()
|
| 1346 |
-
self.myClosingWindow.show()
|
| 1347 |
-
except Exception as e:
|
| 1348 |
-
show_error("closeFunction() in main", e)
|
| 1349 |
-
|
| 1350 |
-
def close_app(self):
|
| 1351 |
-
try:
|
| 1352 |
-
# Attempt to close the NCBI window if it exists
|
| 1353 |
-
try:
|
| 1354 |
-
self.ncbi.close()
|
| 1355 |
-
except Exception as e:
|
| 1356 |
-
print("No NCBI window to close.")
|
| 1357 |
-
|
| 1358 |
-
# Proceed with other closing operations
|
| 1359 |
-
self.closeFunction()
|
| 1360 |
-
self.close()
|
| 1361 |
-
except Exception as e:
|
| 1362 |
-
show_error("close_app() in main", e)
|
| 1363 |
-
|
| 1364 |
-
#startup window class
|
| 1365 |
-
class StartupWindow(QtWidgets.QMainWindow):
|
| 1366 |
-
def __init__(self):
|
| 1367 |
-
try:
|
| 1368 |
-
super(StartupWindow, self).__init__()
|
| 1369 |
-
|
| 1370 |
-
#load UX files
|
| 1371 |
-
try:
|
| 1372 |
-
uic.loadUi(GlobalSettings.appdir + 'startupCASPER.ui', self)
|
| 1373 |
-
self.setWindowIcon(QtGui.QIcon(GlobalSettings.appdir + "cas9image.png"))
|
| 1374 |
-
except Exception as e:
|
| 1375 |
-
logger.critical("Unable to load UX files for Startup Window.")
|
| 1376 |
-
logger.critical(e)
|
| 1377 |
-
logger.critical(traceback.format_exc())
|
| 1378 |
-
exit(-1)
|
| 1379 |
-
|
| 1380 |
-
#set "Main" button to be the default highlighted button on startup
|
| 1381 |
-
self.goToMain.setDefault(True)
|
| 1382 |
-
|
| 1383 |
-
#get current directory, and update based on current operating system
|
| 1384 |
-
self.currentDirectory = os.getcwd()
|
| 1385 |
-
self.databaseDirectory = self.loadDatabaseDirectory()
|
| 1386 |
-
GlobalSettings.CSPR_DB = self.databaseDirectory
|
| 1387 |
-
if platform.system() == "Windows":
|
| 1388 |
-
GlobalSettings.CSPR_DB = GlobalSettings.CSPR_DB.replace("/","\\")
|
| 1389 |
-
else:
|
| 1390 |
-
GlobalSettings.CSPR_DB = GlobalSettings.CSPR_DB.replace("\\","/")
|
| 1391 |
-
|
| 1392 |
-
#setup event handlers for startup buttons
|
| 1393 |
-
self.currentDirText.setText(self.databaseDirectory)
|
| 1394 |
-
self.changeDir.clicked.connect(self.change_directory)
|
| 1395 |
-
self.goToMain.clicked.connect(self.launchMainWindow)
|
| 1396 |
-
self.goToNewGenome.clicked.connect(self.launchNewGenome)
|
| 1397 |
-
|
| 1398 |
-
self.setWindowTitle("CASPER")
|
| 1399 |
-
self.setWindowIcon(Qt.QIcon(GlobalSettings.appdir + "cas9image.ico"))
|
| 1400 |
-
|
| 1401 |
-
#scale UI
|
| 1402 |
-
scale_ui(self)
|
| 1403 |
-
|
| 1404 |
-
except Exception as e:
|
| 1405 |
-
logger.critical("Error initializing StartupWindow class.")
|
| 1406 |
-
logger.critical(e)
|
| 1407 |
-
logger.critical(traceback.format_exc())
|
| 1408 |
-
exit(-1)
|
| 1409 |
-
|
| 1410 |
-
#event handler for user clicking the "Change..." button - used for changing CASPER database directory
|
| 1411 |
-
def change_directory(self):
|
| 1412 |
-
try:
|
| 1413 |
-
# Launch OS file browser
|
| 1414 |
-
newDirectory = QtWidgets.QFileDialog.getExistingDirectory(
|
| 1415 |
-
self, "Open a folder...", self.databaseDirectory, QtWidgets.QFileDialog.ShowDirsOnly)
|
| 1416 |
-
|
| 1417 |
-
# Check if selected path is a directory in the system
|
| 1418 |
-
if not os.path.isdir(newDirectory):
|
| 1419 |
-
show_message(
|
| 1420 |
-
fontSize=self.fontSize,
|
| 1421 |
-
icon=QtWidgets.QMessageBox.Icon.Critical,
|
| 1422 |
-
title="Not a directory",
|
| 1423 |
-
message="The directory you selected does not exist.",
|
| 1424 |
-
)
|
| 1425 |
-
return
|
| 1426 |
-
|
| 1427 |
-
# Ensure directory contains correct filepath format based on OS
|
| 1428 |
-
newDirectory = newDirectory.replace("/", "\\") if platform.system() == "Windows" else newDirectory.replace("\\", "/")
|
| 1429 |
-
|
| 1430 |
-
# Update text edit showing the current selected database directory
|
| 1431 |
-
self.currentDirText.setText(newDirectory)
|
| 1432 |
-
|
| 1433 |
-
# Update CASPER database directories
|
| 1434 |
-
self.databaseDirectory = newDirectory
|
| 1435 |
-
GlobalSettings.CSPR_DB = newDirectory
|
| 1436 |
-
|
| 1437 |
-
except Exception as e:
|
| 1438 |
-
show_error("change_directory() in startup window", e)
|
| 1439 |
-
|
| 1440 |
-
#function for loading the default database directory specified in CASPERinfo
|
| 1441 |
-
#returns: default database parsed from CASPERinfo
|
| 1442 |
-
def loadDatabaseDirectory(self):
|
| 1443 |
-
casperInfoPath = os.path.join(GlobalSettings.appdir, "CASPERinfo")
|
| 1444 |
-
defaultDirectory = "Where would you like to store CASPER database files?" # Default message if directory not found
|
| 1445 |
-
|
| 1446 |
-
try:
|
| 1447 |
-
with open(casperInfoPath, 'r') as file:
|
| 1448 |
-
for line in file:
|
| 1449 |
-
if 'DIRECTORY:' in line:
|
| 1450 |
-
defaultDirectory = line.strip().replace("DIRECTORY:", "").strip()
|
| 1451 |
-
break
|
| 1452 |
-
|
| 1453 |
-
# Ensure the directory path is formatted correctly based on the operating system
|
| 1454 |
-
if platform.system() == "Windows":
|
| 1455 |
-
defaultDirectory = defaultDirectory.replace("/", "\\")
|
| 1456 |
-
else:
|
| 1457 |
-
defaultDirectory = defaultDirectory.replace("\\", "/")
|
| 1458 |
-
|
| 1459 |
-
logger.debug("Successfully parsed CASPERinfo for default database directory.")
|
| 1460 |
-
return defaultDirectory
|
| 1461 |
-
|
| 1462 |
-
except Exception as e:
|
| 1463 |
-
logger.error(f"Error reading {casperInfoPath}: {e}")
|
| 1464 |
-
logger.error(traceback.format_exc())
|
| 1465 |
-
|
| 1466 |
-
return defaultDirectory
|
| 1467 |
-
|
| 1468 |
-
#function for saving the currently selected database directory to CASPERinfo to be the new default value on startup
|
| 1469 |
-
def saveDatabaseDirectory(self):
|
| 1470 |
-
try:
|
| 1471 |
-
#variable to hold the CASPERinfo data with new default directory change
|
| 1472 |
-
CASPERInfoNewData = ""
|
| 1473 |
-
|
| 1474 |
-
#new default directory string for CASPERinfo
|
| 1475 |
-
newDefaultDirectory = "DIRECTORY:" + str(self.databaseDirectory)
|
| 1476 |
-
|
| 1477 |
-
#open CASPERinfo file to read in the files data and add in new change
|
| 1478 |
-
try:
|
| 1479 |
-
CASPERInfo = open(GlobalSettings.appdir + "CASPERinfo", 'r+')
|
| 1480 |
-
CASPERinfoData = CASPERInfo.read()
|
| 1481 |
-
CASPERinfoData = CASPERinfoData.split('\n')
|
| 1482 |
-
for line in CASPERinfoData:
|
| 1483 |
-
#if directory line found, use new default directory string instead
|
| 1484 |
-
if 'DIRECTORY:' in line:
|
| 1485 |
-
CASPERInfoNewData = CASPERInfoNewData + "\n" + newDefaultDirectory
|
| 1486 |
-
else:
|
| 1487 |
-
CASPERInfoNewData = CASPERInfoNewData + "\n" + line
|
| 1488 |
-
CASPERInfoNewData = CASPERInfoNewData[1:]
|
| 1489 |
-
|
| 1490 |
-
#close CASPERinfo
|
| 1491 |
-
CASPERInfo.close()
|
| 1492 |
-
|
| 1493 |
-
#re-open the file and re-write it with current changes
|
| 1494 |
-
CASPERInfo = open(GlobalSettings.appdir + "CASPERinfo", 'w+')
|
| 1495 |
-
CASPERInfo.write(CASPERInfoNewData)
|
| 1496 |
-
CASPERInfo.close()
|
| 1497 |
-
logger.debug("Successfully updated CASPERinfo with new default database directory.")
|
| 1498 |
-
except Exception as e:
|
| 1499 |
-
logger.critical("Unable to write to CASPERinfo file to update database directory.")
|
| 1500 |
-
logger.critical(e)
|
| 1501 |
-
logger.critical(traceback.format_exc())
|
| 1502 |
-
msgBox = QtWidgets.QMessageBox()
|
| 1503 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 1504 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 1505 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 1506 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 1507 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 1508 |
-
msgBox.exec()
|
| 1509 |
-
|
| 1510 |
-
exit(-1)
|
| 1511 |
-
except Exception as e:
|
| 1512 |
-
logger.critical("Error in saveDatabaseDirectory() in startup window.")
|
| 1513 |
-
logger.critical(e)
|
| 1514 |
-
logger.critical(traceback.format_exc())
|
| 1515 |
-
msgBox = QtWidgets.QMessageBox()
|
| 1516 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 1517 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 1518 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 1519 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 1520 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 1521 |
-
msgBox.exec()
|
| 1522 |
-
|
| 1523 |
-
exit(-1)
|
| 1524 |
-
|
| 1525 |
-
# Event handler for user clicking the "New Genome" button - used for launching New Genome
|
| 1526 |
-
def launchNewGenome(self):
|
| 1527 |
-
try:
|
| 1528 |
-
# Make sure database directory variable is up-to-date based on what the user has in the text edit
|
| 1529 |
-
self.databaseDirectory = str(self.currentDirText.text())
|
| 1530 |
-
|
| 1531 |
-
if not os.path.isdir(self.databaseDirectory):
|
| 1532 |
-
show_message(
|
| 1533 |
-
fontSize=12,
|
| 1534 |
-
icon=QtWidgets.QMessageBox.Icon.Critical,
|
| 1535 |
-
title="Not a directory",
|
| 1536 |
-
message="The directory you selected does not exist.",
|
| 1537 |
-
)
|
| 1538 |
-
return
|
| 1539 |
-
|
| 1540 |
-
# Change directories to the specified database directory provided
|
| 1541 |
-
os.chdir(self.databaseDirectory)
|
| 1542 |
-
|
| 1543 |
-
# Write out the database directory to CASPERinfo to be the new default loaded value
|
| 1544 |
-
self.saveDatabaseDirectory()
|
| 1545 |
-
|
| 1546 |
-
# Update global database variable
|
| 1547 |
-
GlobalSettings.CSPR_DB = self.databaseDirectory
|
| 1548 |
-
|
| 1549 |
-
# Create app directories
|
| 1550 |
-
initialize_app_directories()
|
| 1551 |
-
|
| 1552 |
-
# Launch New Genome window
|
| 1553 |
-
self.launch_new_genome()
|
| 1554 |
-
|
| 1555 |
-
self.close()
|
| 1556 |
-
except Exception as e:
|
| 1557 |
-
show_error("launchNewGenome() in startup window", e)
|
| 1558 |
-
|
| 1559 |
-
def launch_new_genome(self):
|
| 1560 |
-
try:
|
| 1561 |
-
GlobalSettings.mainWindow.launch_newGenome()
|
| 1562 |
-
logger.debug("Successfully initialized New Genome in startup window.")
|
| 1563 |
-
except Exception as e:
|
| 1564 |
-
show_error("launch_new_genome() in startup window", e)
|
| 1565 |
-
|
| 1566 |
-
# Event handler for user clicking "Main Program" button - used to launch Main Window
|
| 1567 |
-
def launchMainWindow(self):
|
| 1568 |
-
try:
|
| 1569 |
-
# Make sure database directory variable is up-to-date based on what the user has in the text edit
|
| 1570 |
-
self.databaseDirectory = str(self.currentDirText.text())
|
| 1571 |
-
|
| 1572 |
-
# Make sure the path is a valid path before launching New Genome
|
| 1573 |
-
if not os.path.isdir(self.databaseDirectory):
|
| 1574 |
-
show_message(
|
| 1575 |
-
fontSize=12,
|
| 1576 |
-
icon=QtWidgets.QMessageBox.Icon.Critical,
|
| 1577 |
-
title="Not a directory",
|
| 1578 |
-
message="The directory you selected does not exist.",
|
| 1579 |
-
)
|
| 1580 |
-
return
|
| 1581 |
-
|
| 1582 |
-
# Check if database directory has CSPR files in it
|
| 1583 |
-
if not any(file.endswith(".cspr") for file in os.listdir(self.databaseDirectory)):
|
| 1584 |
-
show_message(
|
| 1585 |
-
fontSize=12,
|
| 1586 |
-
icon=QtWidgets.QMessageBox.Icon.Critical,
|
| 1587 |
-
title="Directory is invalid!",
|
| 1588 |
-
message="You must select a directory with CSPR Files!",
|
| 1589 |
-
)
|
| 1590 |
-
return
|
| 1591 |
-
|
| 1592 |
-
# Change directory to database directory
|
| 1593 |
-
os.chdir(self.databaseDirectory)
|
| 1594 |
-
|
| 1595 |
-
# Update database directory global variable
|
| 1596 |
-
GlobalSettings.CSPR_DB = self.databaseDirectory
|
| 1597 |
-
|
| 1598 |
-
# Save database directory to CASPERinfo
|
| 1599 |
-
self.saveDatabaseDirectory()
|
| 1600 |
-
|
| 1601 |
-
initialize_app_directories()
|
| 1602 |
-
|
| 1603 |
-
# Fill in organism/endo/annotation dropdown information for main, mulit-targeting, and populatin analysis
|
| 1604 |
-
self.load_dropdown_data()
|
| 1605 |
-
|
| 1606 |
-
# Show main window
|
| 1607 |
-
if GlobalSettings.mainWindow.first_show:
|
| 1608 |
-
GlobalSettings.mainWindow.first_show = False
|
| 1609 |
-
GlobalSettings.mainWindow.show()
|
| 1610 |
-
self.close()
|
| 1611 |
-
|
| 1612 |
-
except Exception as e:
|
| 1613 |
-
show_error("launchMainWindow() in startup window", e)
|
| 1614 |
-
|
| 1615 |
-
def load_dropdown_data(self):
|
| 1616 |
-
try:
|
| 1617 |
-
GlobalSettings.mainWindow.getData()
|
| 1618 |
-
GlobalSettings.mainWindow.fill_annotation_dropdown()
|
| 1619 |
-
logger.debug("Successfully loaded organism/endo/annotation drop down information in Main.")
|
| 1620 |
-
except Exception as e:
|
| 1621 |
-
show_error("load_dropdown_data() in Main", e)
|
| 1622 |
-
|
| 1623 |
-
try:
|
| 1624 |
-
GlobalSettings.MTWin.launch()
|
| 1625 |
-
logger.debug("Successfully loaded organism/endo drop down information in Multi-targeting.")
|
| 1626 |
-
except Exception as e:
|
| 1627 |
-
show_error("load_dropdown_data() in Multi-targeting", e)
|
| 1628 |
-
|
| 1629 |
-
try:
|
| 1630 |
-
GlobalSettings.pop_Analysis.launch()
|
| 1631 |
-
logger.debug("Successfully loaded organism/endo drop down information in Population Analysis.")
|
| 1632 |
-
except Exception as e:
|
| 1633 |
-
show_error("load_dropdown_data() in Population Analysis", e)
|
| 1634 |
-
|
| 1635 |
-
def initialize_app_directories():
|
| 1636 |
-
required_dirs = ["FNA", "GBFF"]
|
| 1637 |
-
for directory in required_dirs:
|
| 1638 |
-
path = os.path.join(GlobalSettings.CSPR_DB, directory)
|
| 1639 |
-
if not os.path.exists(path):
|
| 1640 |
-
os.makedirs(path, exist_ok=True)
|
| 1641 |
-
logging.info(f"Directory created: {path}")
|
| 1642 |
-
|
| 1643 |
def setup_logger():
|
| 1644 |
logger.info(f"System OS: {platform.system()}")
|
| 1645 |
|
| 1646 |
if hasattr(sys, 'frozen'):
|
| 1647 |
-
#log CASPER is in packaged format
|
| 1648 |
logger.info("Running a packaged version of CASPER.")
|
| 1649 |
GlobalSettings.appdir = sys.executable
|
| 1650 |
if platform.system() == 'Windows':
|
|
@@ -1653,11 +27,10 @@ def setup_logger():
|
|
| 1653 |
GlobalSettings.appdir = GlobalSettings.appdir[:GlobalSettings.appdir.rfind("Contents/") + 9] + "Resources/"
|
| 1654 |
|
| 1655 |
else:
|
| 1656 |
-
# log CASPER is not in packaged format
|
| 1657 |
logger.info("Running a non-packaged version of CASPER.")
|
| 1658 |
GlobalSettings.appdir = os.path.dirname(os.path.abspath(__file__)) + ('\\' if platform.system() == 'Windows' else '/')
|
| 1659 |
|
| 1660 |
-
fh = logging.FileHandler(GlobalSettings.appdir + 'logs/
|
| 1661 |
fh_formatter = logging.Formatter('%(asctime)s %(levelname)s %(lineno)d:%(filename)s(%(process)d) - %(message)s')
|
| 1662 |
fh.setFormatter(fh_formatter)
|
| 1663 |
fh.setLevel(logging.DEBUG)
|
|
|
|
|
|
|
| 1 |
import sys
|
| 2 |
import os
|
|
|
|
| 3 |
from PyQt5 import QtWidgets, Qt, QtGui, QtCore, uic
|
| 4 |
+
import models.GlobalSettings as GlobalSettings
|
| 5 |
+
import controllers.multitargeting as multitargeting
|
| 6 |
+
import controllers.populationAnalysis as populationAnalysis
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 7 |
import platform
|
|
|
|
|
|
|
|
|
|
|
|
|
| 8 |
import logging
|
| 9 |
+
from utils.ui import show_error, center_ui
|
| 10 |
+
from views.annotation_functions import *
|
| 11 |
+
from views.StartupWindow import StartupWindow
|
| 12 |
+
from views.CMainWindow import CMainWindow
|
| 13 |
|
|
|
|
| 14 |
logger = GlobalSettings.logger
|
| 15 |
|
| 16 |
fontSize = 12
|
| 17 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 18 |
def setup_logger():
|
| 19 |
logger.info(f"System OS: {platform.system()}")
|
| 20 |
|
| 21 |
if hasattr(sys, 'frozen'):
|
|
|
|
| 22 |
logger.info("Running a packaged version of CASPER.")
|
| 23 |
GlobalSettings.appdir = sys.executable
|
| 24 |
if platform.system() == 'Windows':
|
|
|
|
| 27 |
GlobalSettings.appdir = GlobalSettings.appdir[:GlobalSettings.appdir.rfind("Contents/") + 9] + "Resources/"
|
| 28 |
|
| 29 |
else:
|
|
|
|
| 30 |
logger.info("Running a non-packaged version of CASPER.")
|
| 31 |
GlobalSettings.appdir = os.path.dirname(os.path.abspath(__file__)) + ('\\' if platform.system() == 'Windows' else '/')
|
| 32 |
|
| 33 |
+
fh = logging.FileHandler(GlobalSettings.appdir + 'logs/app.log', mode='w')
|
| 34 |
fh_formatter = logging.Formatter('%(asctime)s %(levelname)s %(lineno)d:%(filename)s(%(process)d) - %(message)s')
|
| 35 |
fh.setFormatter(fh_formatter)
|
| 36 |
fh.setLevel(logging.DEBUG)
|
|
@@ -1,18 +1,14 @@
|
|
| 1 |
-
from Algorithms import SeqTranslate
|
| 2 |
import gzip
|
| 3 |
|
| 4 |
##################################################################################################################################
|
| 5 |
-
# CLASS NAME: CSPRparser
|
| 6 |
# Use: Use as a parser for the cspr files
|
| 7 |
# Precondition: Only to the used with .cspr files. Will not work with any other files
|
| 8 |
# This class also took some of the parsing functions from with classes (Multitargeting and Results) and stores them in here
|
| 9 |
##################################################################################################################################
|
| 10 |
|
| 11 |
class CSPRparser:
|
| 12 |
-
|
| 13 |
def __init__(self, inputFileName):
|
| 14 |
-
|
| 15 |
-
# variables used in this class
|
| 16 |
self.multiSum = 0 # multitargetting sum taken from the previous version of make_graphs
|
| 17 |
self.multiCount = 0 # multitargetting count taken from the previous version of make_graphs
|
| 18 |
self.seqTrans = SeqTranslate() # SeqTranslate variable. for decrompressing the data
|
|
|
|
| 1 |
+
from utils.Algorithms import SeqTranslate
|
| 2 |
import gzip
|
| 3 |
|
| 4 |
##################################################################################################################################
|
|
|
|
| 5 |
# Use: Use as a parser for the cspr files
|
| 6 |
# Precondition: Only to the used with .cspr files. Will not work with any other files
|
| 7 |
# This class also took some of the parsing functions from with classes (Multitargeting and Results) and stores them in here
|
| 8 |
##################################################################################################################################
|
| 9 |
|
| 10 |
class CSPRparser:
|
|
|
|
| 11 |
def __init__(self, inputFileName):
|
|
|
|
|
|
|
| 12 |
self.multiSum = 0 # multitargetting sum taken from the previous version of make_graphs
|
| 13 |
self.multiCount = 0 # multitargetting count taken from the previous version of make_graphs
|
| 14 |
self.seqTrans = SeqTranslate() # SeqTranslate variable. for decrompressing the data
|
|
File without changes
|
|
@@ -1,1686 +0,0 @@
|
|
| 1 |
-
from Bio import Entrez
|
| 2 |
-
from bs4 import BeautifulSoup
|
| 3 |
-
from PyQt5 import QtWidgets, Qt, QtCore, uic
|
| 4 |
-
from ftplib import FTP
|
| 5 |
-
import gzip
|
| 6 |
-
import pandas as pd
|
| 7 |
-
import shutil
|
| 8 |
-
import os, time
|
| 9 |
-
import ssl
|
| 10 |
-
import GlobalSettings
|
| 11 |
-
import platform
|
| 12 |
-
import traceback
|
| 13 |
-
import math
|
| 14 |
-
|
| 15 |
-
#global logger
|
| 16 |
-
logger = GlobalSettings.logger
|
| 17 |
-
|
| 18 |
-
ssl._create_default_https_context = ssl._create_unverified_context
|
| 19 |
-
|
| 20 |
-
Entrez.email = "casper2informatics@gmail.com"
|
| 21 |
-
|
| 22 |
-
#model for filtering columns in ncbi table
|
| 23 |
-
class CustomProxyModel(QtCore.QSortFilterProxyModel):
|
| 24 |
-
|
| 25 |
-
def __init__(self, parent=None):
|
| 26 |
-
try:
|
| 27 |
-
super().__init__(parent)
|
| 28 |
-
self._filters = dict()
|
| 29 |
-
except Exception as e:
|
| 30 |
-
logger.critical("Error initializing CustomProxyModel class in ncbi tool.")
|
| 31 |
-
logger.critical(e)
|
| 32 |
-
logger.critical(traceback.format_exc())
|
| 33 |
-
msgBox = QtWidgets.QMessageBox()
|
| 34 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 35 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 36 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 37 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 38 |
-
msgBox.addButton(QtWidge/ts.QMessageBox.StandardButton.Close)
|
| 39 |
-
msgBox.exec()
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
exit(-1)
|
| 43 |
-
|
| 44 |
-
@property
|
| 45 |
-
def filters(self):
|
| 46 |
-
try:
|
| 47 |
-
return self._filters
|
| 48 |
-
except Exception as e:
|
| 49 |
-
logger.critical("Error in filter() in custom proxy model in ncbi tool.")
|
| 50 |
-
logger.critical(e)
|
| 51 |
-
logger.critical(traceback.format_exc())
|
| 52 |
-
msgBox = QtWidgets.QMessageBox()
|
| 53 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 54 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 55 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 56 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 57 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 58 |
-
msgBox.exec()
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
exit(-1)
|
| 62 |
-
|
| 63 |
-
def setFilter(self, expresion, column):
|
| 64 |
-
try:
|
| 65 |
-
if expresion:
|
| 66 |
-
self.filters[column] = expresion
|
| 67 |
-
elif column in self.filters:
|
| 68 |
-
del self.filters[column]
|
| 69 |
-
self.invalidateFilter()
|
| 70 |
-
except Exception as e:
|
| 71 |
-
logger.critical("Error in setFilters() in custom proxy model in ncbi tool.")
|
| 72 |
-
logger.critical(e)
|
| 73 |
-
logger.critical(traceback.format_exc())
|
| 74 |
-
msgBox = QtWidgets.QMessageBox()
|
| 75 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 76 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 77 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 78 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 79 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 80 |
-
msgBox.exec()
|
| 81 |
-
|
| 82 |
-
|
| 83 |
-
exit(-1)
|
| 84 |
-
|
| 85 |
-
def filterAcceptsRow(self, source_row, source_parent):
|
| 86 |
-
try:
|
| 87 |
-
for column, expresion in self.filters.items():
|
| 88 |
-
text = self.sourceModel().index(source_row, column, source_parent).data()
|
| 89 |
-
regex = QtCore.QRegExp(
|
| 90 |
-
expresion, QtCore.Qt.CaseInsensitive, QtCore.QRegExp.RegExp
|
| 91 |
-
)
|
| 92 |
-
if regex.indexIn(text) == -1:
|
| 93 |
-
return False
|
| 94 |
-
return True
|
| 95 |
-
|
| 96 |
-
except Exception as e:
|
| 97 |
-
logger.critical("Error in filterAcceptsRow() in custom proxy model in ncbi tool.")
|
| 98 |
-
logger.critical(e)
|
| 99 |
-
logger.critical(traceback.format_exc())
|
| 100 |
-
msgBox = QtWidgets.QMessageBox()
|
| 101 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 102 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 103 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 104 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 105 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 106 |
-
msgBox.exec()
|
| 107 |
-
|
| 108 |
-
|
| 109 |
-
exit(-1)
|
| 110 |
-
|
| 111 |
-
|
| 112 |
-
#model for the data in the ncbi search table
|
| 113 |
-
class PandasModel(QtCore.QAbstractTableModel):
|
| 114 |
-
|
| 115 |
-
def __init__(self, df=pd.DataFrame(), parent=None):
|
| 116 |
-
try:
|
| 117 |
-
QtCore.QAbstractTableModel.__init__(self, parent=parent)
|
| 118 |
-
self._df = df.copy()
|
| 119 |
-
except Exception as e:
|
| 120 |
-
logger.critical("Error initializing PandasModel class in ncbi tool.")
|
| 121 |
-
logger.critical(e)
|
| 122 |
-
logger.critical(traceback.format_exc())
|
| 123 |
-
msgBox = QtWidgets.QMessageBox()
|
| 124 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 125 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 126 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 127 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 128 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 129 |
-
msgBox.exec()
|
| 130 |
-
|
| 131 |
-
|
| 132 |
-
exit(-1)
|
| 133 |
-
|
| 134 |
-
def toDataFrame(self):
|
| 135 |
-
try:
|
| 136 |
-
return self._df.copy()
|
| 137 |
-
|
| 138 |
-
except Exception as e:
|
| 139 |
-
logger.critical("Error in toDataFrame() in Pandas Model in ncbi tool.")
|
| 140 |
-
logger.critical(e)
|
| 141 |
-
logger.critical(traceback.format_exc())
|
| 142 |
-
msgBox = QtWidgets.QMessageBox()
|
| 143 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 144 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 145 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 146 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 147 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 148 |
-
msgBox.exec()
|
| 149 |
-
|
| 150 |
-
|
| 151 |
-
exit(-1)
|
| 152 |
-
|
| 153 |
-
def headerData(self, section, orientation, role=QtCore.Qt.DisplayRole):
|
| 154 |
-
try:
|
| 155 |
-
if role != QtCore.Qt.DisplayRole:
|
| 156 |
-
return QtCore.QVariant()
|
| 157 |
-
|
| 158 |
-
if orientation == QtCore.Qt.Horizontal:
|
| 159 |
-
try:
|
| 160 |
-
return self._df.columns.tolist()[section]
|
| 161 |
-
except (IndexError, ):
|
| 162 |
-
return QtCore.QVariant()
|
| 163 |
-
elif orientation == QtCore.Qt.Vertical:
|
| 164 |
-
try:
|
| 165 |
-
return self._df.index.tolist()[section]
|
| 166 |
-
except (IndexError, ):
|
| 167 |
-
return QtCore.QVariant()
|
| 168 |
-
except Exception as e:
|
| 169 |
-
logger.critical("Error in headerData() in Pandas Model in ncbi tool.")
|
| 170 |
-
logger.critical(e)
|
| 171 |
-
logger.critical(traceback.format_exc())
|
| 172 |
-
msgBox = QtWidgets.QMessageBox()
|
| 173 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 174 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 175 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 176 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 177 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 178 |
-
msgBox.exec()
|
| 179 |
-
|
| 180 |
-
|
| 181 |
-
exit(-1)
|
| 182 |
-
|
| 183 |
-
def data(self, index, role=QtCore.Qt.DisplayRole):
|
| 184 |
-
try:
|
| 185 |
-
if role == QtCore.Qt.TextAlignmentRole:
|
| 186 |
-
return QtCore.Qt.AlignCenter
|
| 187 |
-
if role != QtCore.Qt.DisplayRole:
|
| 188 |
-
return QtCore.QVariant()
|
| 189 |
-
if not index.isValid():
|
| 190 |
-
return QtCore.QVariant()
|
| 191 |
-
|
| 192 |
-
return QtCore.QVariant(str(self._df.iloc[index.row(), index.column()]))
|
| 193 |
-
|
| 194 |
-
except Exception as e:
|
| 195 |
-
logger.critical("Error in data() in Pandas Model in ncbi tool.")
|
| 196 |
-
logger.critical(e)
|
| 197 |
-
logger.critical(traceback.format_exc())
|
| 198 |
-
msgBox = QtWidgets.QMessageBox()
|
| 199 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 200 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 201 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 202 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 203 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 204 |
-
msgBox.exec()
|
| 205 |
-
|
| 206 |
-
|
| 207 |
-
exit(-1)
|
| 208 |
-
|
| 209 |
-
def setData(self, index, value, role):
|
| 210 |
-
try:
|
| 211 |
-
row = self._df.index[index.row()]
|
| 212 |
-
col = self._df.columns[index.column()]
|
| 213 |
-
if hasattr(value, 'toPyObject'):
|
| 214 |
-
# PyQt4 gets a QVariant
|
| 215 |
-
value = value.toPyObject()
|
| 216 |
-
else:
|
| 217 |
-
# PySide gets an unicode
|
| 218 |
-
dtype = self._df[col].dtype
|
| 219 |
-
if dtype != object:
|
| 220 |
-
value = None if value == '' else dtype.type(value)
|
| 221 |
-
self._df.set_value(row, col, value)
|
| 222 |
-
return True
|
| 223 |
-
except Exception as e:
|
| 224 |
-
logger.critical("Error in setData() in Pandas Model in ncbi tool.")
|
| 225 |
-
logger.critical(e)
|
| 226 |
-
logger.critical(traceback.format_exc())
|
| 227 |
-
msgBox = QtWidgets.QMessageBox()
|
| 228 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 229 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 230 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 231 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 232 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 233 |
-
msgBox.exec()
|
| 234 |
-
|
| 235 |
-
|
| 236 |
-
exit(-1)
|
| 237 |
-
|
| 238 |
-
def rowCount(self, parent=QtCore.QModelIndex()):
|
| 239 |
-
try:
|
| 240 |
-
return len(self._df.index)
|
| 241 |
-
|
| 242 |
-
except Exception as e:
|
| 243 |
-
logger.critical("Error in rowCount() in Pandas Model in ncbi tool.")
|
| 244 |
-
logger.critical(e)
|
| 245 |
-
logger.critical(traceback.format_exc())
|
| 246 |
-
msgBox = QtWidgets.QMessageBox()
|
| 247 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 248 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 249 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 250 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 251 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 252 |
-
msgBox.exec()
|
| 253 |
-
|
| 254 |
-
|
| 255 |
-
exit(-1)
|
| 256 |
-
|
| 257 |
-
def columnCount(self, parent=QtCore.QModelIndex()):
|
| 258 |
-
try:
|
| 259 |
-
return len(self._df.columns)
|
| 260 |
-
except Exception as e:
|
| 261 |
-
logger.critical("Error in columnCount() in Pandas Model in ncbi tool.")
|
| 262 |
-
logger.critical(e)
|
| 263 |
-
logger.critical(traceback.format_exc())
|
| 264 |
-
msgBox = QtWidgets.QMessageBox()
|
| 265 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 266 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 267 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 268 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 269 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 270 |
-
msgBox.exec()
|
| 271 |
-
|
| 272 |
-
|
| 273 |
-
exit(-1)
|
| 274 |
-
|
| 275 |
-
def sort(self, column, order):
|
| 276 |
-
try:
|
| 277 |
-
colname = self._df.columns.tolist()[column]
|
| 278 |
-
self.layoutAboutToBeChanged.emit()
|
| 279 |
-
self._df.sort_values(colname, ascending=order, inplace=True)
|
| 280 |
-
self._df.reset_index(inplace=True, drop=True)
|
| 281 |
-
self.layoutChanged.emit()
|
| 282 |
-
except Exception as e:
|
| 283 |
-
logger.critical("Error in sort() in Pandas Model in ncbi tool.")
|
| 284 |
-
logger.critical(e)
|
| 285 |
-
logger.critical(traceback.format_exc())
|
| 286 |
-
msgBox = QtWidgets.QMessageBox()
|
| 287 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 288 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 289 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 290 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 291 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 292 |
-
msgBox.exec()
|
| 293 |
-
|
| 294 |
-
|
| 295 |
-
exit(-1)
|
| 296 |
-
|
| 297 |
-
## Taken from StackOverflow: https://stackoverflow.com/questions/57607072/update-pyqt-progress-from-another-thread-running-ftp-download
|
| 298 |
-
class DownloadThread(QtCore.QThread):
|
| 299 |
-
""" Overall signals """
|
| 300 |
-
finished = QtCore.pyqtSignal(object)
|
| 301 |
-
started = QtCore.pyqtSignal(object)
|
| 302 |
-
|
| 303 |
-
""" Download specific signals """
|
| 304 |
-
data_progress = QtCore.pyqtSignal(object) # This signal emits progress data for the progress bar
|
| 305 |
-
data_size = QtCore.pyqtSignal(object) # This signal emits the size of the file being downloaded
|
| 306 |
-
file_started = QtCore.pyqtSignal(object) # This signal emits when the file starts downloading
|
| 307 |
-
file_finished = QtCore.pyqtSignal(object) # This signal emits the name of the file downloaded
|
| 308 |
-
|
| 309 |
-
def __init__(self,parent,url,id):
|
| 310 |
-
try:
|
| 311 |
-
QtCore.QThread.__init__(self,parent)
|
| 312 |
-
self.id = id # Initialize ID
|
| 313 |
-
self.url = url # Initialize URL
|
| 314 |
-
self.ftp = FTP('ftp.ncbi.nlm.nih.gov') # Initialize FTP object
|
| 315 |
-
self.ftp.login()
|
| 316 |
-
except Exception as e:
|
| 317 |
-
logger.critical("Error initializing Thread class in ncbi tool.")
|
| 318 |
-
logger.critical(e)
|
| 319 |
-
logger.critical(traceback.format_exc())
|
| 320 |
-
msgBox = QtWidgets.QMessageBox()
|
| 321 |
-
msgBox.setStyleSheet("font: " + str(GlobalSettings.mainWindow.ncbi.fontSize) + "pt 'Arial'")
|
| 322 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 323 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 324 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 325 |
-
msgBox.addButton(QtWidge/ts.QMessageBox.StandardButton.Close)
|
| 326 |
-
msgBox.exec()
|
| 327 |
-
exit(-1)
|
| 328 |
-
|
| 329 |
-
def run(self):
|
| 330 |
-
try:
|
| 331 |
-
### Start by making sure the url is valid
|
| 332 |
-
if self.url == "":
|
| 333 |
-
self.finished.emit((self.id, False))
|
| 334 |
-
return
|
| 335 |
-
else:
|
| 336 |
-
self.started.emit(self.id)
|
| 337 |
-
self.ftp.cwd(self.url) # Change to appropriate directory
|
| 338 |
-
dir_files = self.ftp.nlst() # Get list of files in directory
|
| 339 |
-
for file in dir_files: # Loop through every file in the directory
|
| 340 |
-
if GlobalSettings.mainWindow.ncbi.gbff_checkbox.isChecked(): # If a GBFF is supposed to be downloaded
|
| 341 |
-
if file.find('genomic.gbff') != -1: # If a GBFF exists in this directory
|
| 342 |
-
|
| 343 |
-
# check OS for output path
|
| 344 |
-
if platform.system() == "Windows":
|
| 345 |
-
output_file = GlobalSettings.CSPR_DB + "\\GBFF\\" + file
|
| 346 |
-
else:
|
| 347 |
-
output_file = GlobalSettings.CSPR_DB + "/GBFF/" + file
|
| 348 |
-
|
| 349 |
-
self.ftp.voidcmd('TYPE I')
|
| 350 |
-
totalsize = self.ftp.size(file) # Get size of file that is being downloaded
|
| 351 |
-
# The first signal sets the maximum for the progress bar
|
| 352 |
-
self.file_started.emit((self.id,'Downloading GBFF: ' + str(round(totalsize/1e6,2)) + 'MB...',str(totalsize))) # Emit that the file download is starting and size of file
|
| 353 |
-
with open(output_file, 'wb') as self.f:
|
| 354 |
-
self.ftp.retrbinary(f"RETR {file}", self.file_write) # Download the file, emitting progress as we go
|
| 355 |
-
self.decompress_file(output_file) # Decompress the file
|
| 356 |
-
self.file_finished.emit((self.id,'GBFF Downloaded!',output_file)) # Once download is finished, emit signal
|
| 357 |
-
|
| 358 |
-
if GlobalSettings.mainWindow.ncbi.fna_checkbox.isChecked(): # If a FNA is supposed to be downloaded
|
| 359 |
-
if file.find('genomic.fna') != -1 and file.find('_cds_') == -1 and file.find('_rna_') == -1: # If a FNA exists in this directory
|
| 360 |
-
|
| 361 |
-
# check OS for output path
|
| 362 |
-
if platform.system() == "Windows":
|
| 363 |
-
output_file = GlobalSettings.CSPR_DB + "\\FNA\\" + file
|
| 364 |
-
else:
|
| 365 |
-
output_file = GlobalSettings.CSPR_DB + "/FNA/" + file
|
| 366 |
-
|
| 367 |
-
self.ftp.voidcmd('TYPE I')
|
| 368 |
-
totalsize = self.ftp.size(file) # Get size of file that is being downloaded
|
| 369 |
-
self.file_started.emit((self.id,'Downloading FNA: ' + str(round(totalsize/1e6,2)) + 'MB...',str(totalsize))) # Emit that file download is starting
|
| 370 |
-
with open(output_file, 'wb') as self.f:
|
| 371 |
-
self.ftp.retrbinary(f"RETR {file}", self.file_write) # Download the file
|
| 372 |
-
|
| 373 |
-
self.decompress_file(output_file) # Decompress the file
|
| 374 |
-
self.file_finished.emit((self.id,'FNA Downloaded!',output_file)) # Once download is finished, emit signal
|
| 375 |
-
self.finished.emit((self.id,True))
|
| 376 |
-
self.ftp.quit() # Stop the FTP connection once everything has been downloaded
|
| 377 |
-
except Exception as e:
|
| 378 |
-
logger.critical("Error downloading file within DownloadThread class.")
|
| 379 |
-
logger.critical(e)
|
| 380 |
-
logger.critical(traceback.format_exc())
|
| 381 |
-
msgBox = QtWidgets.QMessageBox()
|
| 382 |
-
msgBox.setStyleSheet("font: " + str(GlobalSettings.mainWindow.ncbi.fontSize) + "pt 'Arial'")
|
| 383 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 384 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 385 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 386 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 387 |
-
msgBox.exec()
|
| 388 |
-
exit(-1)
|
| 389 |
-
|
| 390 |
-
def file_write(self, data):
|
| 391 |
-
self.f.write(data) # Write the downloaded data to a file
|
| 392 |
-
# The other signals increase a progress
|
| 393 |
-
self.data_progress.emit((self.id,str(len(data)))) # Emit a signal updating progress
|
| 394 |
-
|
| 395 |
-
# decompress file function
|
| 396 |
-
def decompress_file(self, filename):
|
| 397 |
-
try:
|
| 398 |
-
block_size = 65536
|
| 399 |
-
with gzip.open(filename, 'rb') as f_in:
|
| 400 |
-
with open(str(filename).replace('.gz', ''), 'wb') as f_out:
|
| 401 |
-
while True:
|
| 402 |
-
block = f_in.read(block_size)
|
| 403 |
-
if not block:
|
| 404 |
-
break
|
| 405 |
-
else:
|
| 406 |
-
f_out.write(block)
|
| 407 |
-
os.remove(str(filename))
|
| 408 |
-
except Exception as e:
|
| 409 |
-
logger.critical("Error in decompress_file() in ncbi tool.")
|
| 410 |
-
logger.critical(e)
|
| 411 |
-
logger.critical(traceback.format_exc())
|
| 412 |
-
msgBox = QtWidgets.QMessageBox()
|
| 413 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 414 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 415 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 416 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 417 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 418 |
-
msgBox.exec()
|
| 419 |
-
exit(-1)
|
| 420 |
-
|
| 421 |
-
#ncbi
|
| 422 |
-
class NCBI_search_tool(QtWidgets.QMainWindow):
|
| 423 |
-
|
| 424 |
-
def __init__(self):
|
| 425 |
-
try:
|
| 426 |
-
super(NCBI_search_tool, self).__init__()
|
| 427 |
-
uic.loadUi(GlobalSettings.appdir + 'ncbi.ui', self)
|
| 428 |
-
self.setWindowIcon(Qt.QIcon(GlobalSettings.appdir + "cas9image.ico"))
|
| 429 |
-
self.setWindowTitle("NCBI Download Tool")
|
| 430 |
-
self.logicalIndex = 0
|
| 431 |
-
self.filters = dict()
|
| 432 |
-
self.download_button.clicked.connect(self.download_files_wrapper)
|
| 433 |
-
self.search_button.clicked.connect(self.query_db)
|
| 434 |
-
self.ncbi_table.verticalHeader().hide()
|
| 435 |
-
self.all_rows.clicked.connect(self.select_all)
|
| 436 |
-
self.back_button.clicked.connect(self.go_back)
|
| 437 |
-
self.ncbi_table.setFocusPolicy(QtCore.Qt.NoFocus)
|
| 438 |
-
self.progressBar.setValue(0)
|
| 439 |
-
self.rename_window = rename_window()
|
| 440 |
-
self.rename_window.submit_button.clicked.connect(self.submit_rename)
|
| 441 |
-
self.rename_window.go_back.clicked.connect(self.rename_go_back)
|
| 442 |
-
self.df = pd.DataFrame()
|
| 443 |
-
groupbox_style = """
|
| 444 |
-
QGroupBox:title{subcontrol-origin: margin;
|
| 445 |
-
left: 10px;
|
| 446 |
-
padding: 0 5px 0 5px;}
|
| 447 |
-
QGroupBox#Step1{border: 2px solid rgb(111,181,110);
|
| 448 |
-
border-radius: 9px;
|
| 449 |
-
font: bold 14pt 'Arial';
|
| 450 |
-
margin-top: 10px;}"""
|
| 451 |
-
self.Step1.setStyleSheet(groupbox_style)
|
| 452 |
-
self.Step2.setStyleSheet(groupbox_style.replace("Step1","Step2"))
|
| 453 |
-
self.Step3.setStyleSheet(groupbox_style.replace("Step1","Step3"))
|
| 454 |
-
self.ncbi_table.setSelectionMode(QtWidgets.QAbstractItemView.MultiSelection)
|
| 455 |
-
self.ncbi_table.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
|
| 456 |
-
#navigation page
|
| 457 |
-
self.goToPrompt = goToPrompt()
|
| 458 |
-
self.goToPrompt.stay.clicked.connect(self.stay)
|
| 459 |
-
self.goToPrompt.close.clicked.connect(self.close)
|
| 460 |
-
|
| 461 |
-
#loading label
|
| 462 |
-
self.loading_window = loading_window()
|
| 463 |
-
|
| 464 |
-
|
| 465 |
-
self.genbank_checkbox.toggled.connect(self.check_genbank)
|
| 466 |
-
|
| 467 |
-
#scale UI
|
| 468 |
-
self.first_show = True
|
| 469 |
-
self.scaleUI()
|
| 470 |
-
|
| 471 |
-
except Exception as e:
|
| 472 |
-
logger.critical("Error initializing NCBI_search_tool class.")
|
| 473 |
-
logger.critical(e)
|
| 474 |
-
logger.critical(traceback.format_exc())
|
| 475 |
-
msgBox = QtWidgets.QMessageBox()
|
| 476 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 477 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 478 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 479 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 480 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 481 |
-
msgBox.exec()
|
| 482 |
-
exit(-1)
|
| 483 |
-
|
| 484 |
-
def check_genbank(self):
|
| 485 |
-
if self.genbank_checkbox.isChecked():
|
| 486 |
-
msgBox = QtWidgets.QMessageBox()
|
| 487 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 488 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Warning)
|
| 489 |
-
msgBox.setWindowTitle("Warning!")
|
| 490 |
-
msgBox.setText("Warning!\n\nThe GenBank collection may contain poorly or partially annotated annotation files. We highly recommend using the RefSeq collection if it is available.")
|
| 491 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Ok)
|
| 492 |
-
msgBox.exec()
|
| 493 |
-
else:
|
| 494 |
-
pass # Do nothing
|
| 495 |
-
|
| 496 |
-
#scale UI based on current screen
|
| 497 |
-
def scaleUI(self):
|
| 498 |
-
try:
|
| 499 |
-
self.repaint()
|
| 500 |
-
QtWidgets.QApplication.processEvents()
|
| 501 |
-
|
| 502 |
-
screen = self.screen()
|
| 503 |
-
dpi = screen.physicalDotsPerInch()
|
| 504 |
-
width = screen.geometry().width()
|
| 505 |
-
height = screen.geometry().height()
|
| 506 |
-
|
| 507 |
-
# font scaling
|
| 508 |
-
fontSize = 12
|
| 509 |
-
self.fontSize = fontSize
|
| 510 |
-
self.centralWidget().setStyleSheet("font: " + str(fontSize) + "pt 'Arial';")
|
| 511 |
-
|
| 512 |
-
# CASPER header scaling
|
| 513 |
-
fontSize = 30
|
| 514 |
-
self.title.setStyleSheet("font: bold " + str(fontSize) + "pt 'Arial';")
|
| 515 |
-
|
| 516 |
-
self.adjustSize()
|
| 517 |
-
|
| 518 |
-
currentWidth = self.size().width()
|
| 519 |
-
currentHeight = self.size().height()
|
| 520 |
-
|
| 521 |
-
# window scaling
|
| 522 |
-
# 1920x1080 => 850x750
|
| 523 |
-
scaledWidth = int((width * 1000) / 1920)
|
| 524 |
-
scaledHeight = int((height * 750) / 1080)
|
| 525 |
-
|
| 526 |
-
if scaledHeight < currentHeight:
|
| 527 |
-
scaledHeight = currentHeight
|
| 528 |
-
if scaledWidth < currentWidth:
|
| 529 |
-
scaledWidth = currentWidth
|
| 530 |
-
|
| 531 |
-
screen = QtWidgets.QApplication.desktop().screenNumber(QtWidgets.QApplication.desktop().cursor().pos())
|
| 532 |
-
centerPoint = QtWidgets.QApplication.desktop().screenGeometry(screen).center()
|
| 533 |
-
x = centerPoint.x()
|
| 534 |
-
y = centerPoint.y()
|
| 535 |
-
x = x - (math.ceil(scaledWidth / 2))
|
| 536 |
-
y = y - (math.ceil(scaledHeight / 2))
|
| 537 |
-
self.setGeometry(x, y, scaledWidth, scaledHeight)
|
| 538 |
-
|
| 539 |
-
self.repaint()
|
| 540 |
-
QtWidgets.QApplication.processEvents()
|
| 541 |
-
|
| 542 |
-
except Exception as e:
|
| 543 |
-
logger.critical("Error in scaleUI() in NCBI tool.")
|
| 544 |
-
logger.critical(e)
|
| 545 |
-
logger.critical(traceback.format_exc())
|
| 546 |
-
msgBox = QtWidgets.QMessageBox()
|
| 547 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 548 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 549 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 550 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 551 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 552 |
-
msgBox.exec()
|
| 553 |
-
|
| 554 |
-
|
| 555 |
-
exit(-1)
|
| 556 |
-
|
| 557 |
-
#center UI on current screen
|
| 558 |
-
def centerUI(self):
|
| 559 |
-
try:
|
| 560 |
-
self.repaint()
|
| 561 |
-
QtWidgets.QApplication.processEvents()
|
| 562 |
-
|
| 563 |
-
# center window on current screen
|
| 564 |
-
width = self.width()
|
| 565 |
-
height = self.height()
|
| 566 |
-
screen = QtWidgets.QApplication.desktop().screenNumber(QtWidgets.QApplication.desktop().cursor().pos())
|
| 567 |
-
centerPoint = QtWidgets.QApplication.desktop().screenGeometry(screen).center()
|
| 568 |
-
x = centerPoint.x()
|
| 569 |
-
y = centerPoint.y()
|
| 570 |
-
x = x - (math.ceil(width / 2))
|
| 571 |
-
y = y - (math.ceil(height / 2))
|
| 572 |
-
self.setGeometry(x, y, width, height)
|
| 573 |
-
|
| 574 |
-
self.repaint()
|
| 575 |
-
QtWidgets.QApplication.processEvents()
|
| 576 |
-
except Exception as e:
|
| 577 |
-
logger.critical("Error in centerUI() in NCBI tool.")
|
| 578 |
-
logger.critical(e)
|
| 579 |
-
logger.critical(traceback.format_exc())
|
| 580 |
-
msgBox = QtWidgets.QMessageBox()
|
| 581 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 582 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 583 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 584 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 585 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 586 |
-
msgBox.exec()
|
| 587 |
-
|
| 588 |
-
|
| 589 |
-
exit(-1)
|
| 590 |
-
|
| 591 |
-
def go_back(self):
|
| 592 |
-
try:
|
| 593 |
-
""" Clear table """
|
| 594 |
-
self.df = pd.DataFrame() ###Make empty DF
|
| 595 |
-
self.model = PandasModel(self.df)
|
| 596 |
-
self.proxy = CustomProxyModel(self)
|
| 597 |
-
self.proxy.setSourceModel(self.model)
|
| 598 |
-
self.ncbi_table.setModel(self.proxy)
|
| 599 |
-
self.ncbi_table.verticalHeader().hide()
|
| 600 |
-
""" Clear all line edits """
|
| 601 |
-
self.organism_line_edit.clear()
|
| 602 |
-
self.infra_name_line_edit.clear()
|
| 603 |
-
self.ret_max_line_edit.setText("100")
|
| 604 |
-
self.infra_name_line_edit.clear()
|
| 605 |
-
""" Reset all checkboxes """
|
| 606 |
-
self.yes_box.setChecked(False)
|
| 607 |
-
self.genbank_checkbox.setChecked(False)
|
| 608 |
-
self.refseq_checkbox.setChecked(False)
|
| 609 |
-
self.gbff_checkbox.setChecked(False)
|
| 610 |
-
self.fna_checkbox.setChecked(False)
|
| 611 |
-
""" Hide window """
|
| 612 |
-
self.close()
|
| 613 |
-
except Exception as e:
|
| 614 |
-
logger.critical("Error in go_back() in ncbi tool.")
|
| 615 |
-
logger.critical(e)
|
| 616 |
-
logger.critical(traceback.format_exc())
|
| 617 |
-
msgBox = QtWidgets.QMessageBox()
|
| 618 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 619 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 620 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 621 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 622 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 623 |
-
msgBox.exec()
|
| 624 |
-
|
| 625 |
-
|
| 626 |
-
exit(-1)
|
| 627 |
-
|
| 628 |
-
@QtCore.pyqtSlot()
|
| 629 |
-
def query_db(self):
|
| 630 |
-
try:
|
| 631 |
-
#show loading
|
| 632 |
-
self.loading_window.loading_bar.setValue(5)
|
| 633 |
-
self.loading_window.centerUI()
|
| 634 |
-
self.loading_window.show()
|
| 635 |
-
QtCore.QCoreApplication.processEvents()
|
| 636 |
-
|
| 637 |
-
#setup table
|
| 638 |
-
self.comboBox = QtWidgets.QComboBox(self)
|
| 639 |
-
self.horizontalHeader = self.ncbi_table.horizontalHeader()
|
| 640 |
-
self.horizontalHeader.sectionClicked.connect(self.on_view_horizontalHeader_sectionClicked)
|
| 641 |
-
|
| 642 |
-
#Build Query commands
|
| 643 |
-
retmax = int(self.ret_max_line_edit.text())
|
| 644 |
-
if retmax == "":
|
| 645 |
-
retmax = 100
|
| 646 |
-
org = self.organism_line_edit.text()
|
| 647 |
-
term = '"' + org + '"[Organism]'
|
| 648 |
-
if self.yes_box.isChecked():
|
| 649 |
-
term += ' AND "Complete Genome"[Assembly Level]'
|
| 650 |
-
if self.infra_name_line_edit.text() != "":
|
| 651 |
-
term += ' AND "' + self.infra_name_line_edit.text() + '"[Infraspecific name]'
|
| 652 |
-
|
| 653 |
-
#Search DB for IDs
|
| 654 |
-
handle = Entrez.esearch(db="assembly", retmax=retmax, term=term)
|
| 655 |
-
content = handle.readlines()
|
| 656 |
-
content = "".join(str(content))
|
| 657 |
-
#bs_content = BeautifulSoup(content, "lxml")
|
| 658 |
-
bs_content = BeautifulSoup(content, "html.parser")
|
| 659 |
-
|
| 660 |
-
self.loading_window.loading_bar.setValue(20)
|
| 661 |
-
QtCore.QCoreApplication.processEvents()
|
| 662 |
-
|
| 663 |
-
#Extract IDs
|
| 664 |
-
idlist = bs_content.find('idlist')
|
| 665 |
-
ids = idlist.find_all('id')
|
| 666 |
-
ids = [i.text for i in ids]
|
| 667 |
-
|
| 668 |
-
self.loading_window.loading_bar.setValue(35)
|
| 669 |
-
QtCore.QCoreApplication.processEvents()
|
| 670 |
-
|
| 671 |
-
# Get Details on IDs
|
| 672 |
-
handle = Entrez.esummary(db="assembly", id=','.join(ids))
|
| 673 |
-
content = handle.readlines()
|
| 674 |
-
handle.close()
|
| 675 |
-
content = "".join(str(content))
|
| 676 |
-
#bs_content = BeautifulSoup(content, 'lxml')
|
| 677 |
-
bs_content = BeautifulSoup(content, "html.parser")
|
| 678 |
-
|
| 679 |
-
self.loading_window.loading_bar.setValue(55)
|
| 680 |
-
|
| 681 |
-
QtCore.QCoreApplication.processEvents()
|
| 682 |
-
|
| 683 |
-
#Prep Data for Table
|
| 684 |
-
assembly_name = bs_content.find_all('assemblyname')
|
| 685 |
-
genbank_ids = bs_content.find_all('genbank')
|
| 686 |
-
refseq_ids = bs_content.find_all('refseq')
|
| 687 |
-
assembly_status = bs_content.find_all('assemblystatus')
|
| 688 |
-
species_name = bs_content.find_all('speciesname')
|
| 689 |
-
temp_strains = bs_content.find_all('infraspecieslist')
|
| 690 |
-
assembly_name = [i.text for i in assembly_name]
|
| 691 |
-
genbank_ids = [i.text for i in genbank_ids]
|
| 692 |
-
refseq_ids = [i.text for i in refseq_ids]
|
| 693 |
-
assembly_status = [i.text for i in assembly_status]
|
| 694 |
-
species_name = [i.text for i in species_name]
|
| 695 |
-
ids = [int(i) for i in ids]
|
| 696 |
-
strains = []
|
| 697 |
-
for i in range(len(genbank_ids)):
|
| 698 |
-
temp_str = str(temp_strains[i])
|
| 699 |
-
#temp_str = BeautifulSoup(temp_str, 'lxml')
|
| 700 |
-
temp_str = BeautifulSoup(temp_str, 'html.parser')
|
| 701 |
-
temp_str = temp_str.find('sub_value')
|
| 702 |
-
if temp_str != None:
|
| 703 |
-
strains.append(temp_str.text)
|
| 704 |
-
else:
|
| 705 |
-
strains.append('N/A')
|
| 706 |
-
|
| 707 |
-
self.loading_window.loading_bar.setValue(65)
|
| 708 |
-
QtCore.QCoreApplication.processEvents()
|
| 709 |
-
|
| 710 |
-
#Get ftp links
|
| 711 |
-
genbank_links = bs_content.find_all('ftppath_genbank')
|
| 712 |
-
refseq_links = bs_content.find_all('ftppath_refseq')
|
| 713 |
-
refseq_links = bs_content.find_all('ftppath_refseq')
|
| 714 |
-
genbank_links = [i.text for i in genbank_links]
|
| 715 |
-
refseq_links = [i.text for i in refseq_links]
|
| 716 |
-
self.genbank_ftp_dict = {}
|
| 717 |
-
self.refseq_ftp_dict = {}
|
| 718 |
-
for i in range(len(ids)):
|
| 719 |
-
if genbank_ids[i] == '':
|
| 720 |
-
self.genbank_ftp_dict[ids[i]] = ''
|
| 721 |
-
else:
|
| 722 |
-
self.genbank_ftp_dict[ids[i]] = genbank_links[i] + '/'
|
| 723 |
-
if refseq_ids[i] == '':
|
| 724 |
-
self.refseq_ftp_dict[ids[i]] = ''
|
| 725 |
-
else:
|
| 726 |
-
self.refseq_ftp_dict[ids[i]] = refseq_links[i] + '/'
|
| 727 |
-
|
| 728 |
-
self.loading_window.loading_bar.setValue(80)
|
| 729 |
-
QtCore.QCoreApplication.processEvents()
|
| 730 |
-
|
| 731 |
-
#Build dataframe
|
| 732 |
-
self.df = pd.DataFrame({'ID': ids,
|
| 733 |
-
'Species Name' : species_name,
|
| 734 |
-
'Strain' : strains,
|
| 735 |
-
'Assembly Name' : assembly_name,
|
| 736 |
-
'GenBank assembly accession': genbank_ids,
|
| 737 |
-
'RefSeq assembly accession': refseq_ids,
|
| 738 |
-
'Assembly Status': assembly_status})
|
| 739 |
-
|
| 740 |
-
self.loading_window.loading_bar.setValue(90)
|
| 741 |
-
QtCore.QCoreApplication.processEvents()
|
| 742 |
-
|
| 743 |
-
#Build table view
|
| 744 |
-
self.df.replace('', 'N/A', inplace=True)
|
| 745 |
-
self.model = PandasModel(self.df)
|
| 746 |
-
self.proxy = CustomProxyModel(self)
|
| 747 |
-
self.proxy.setSourceModel(self.model)
|
| 748 |
-
self.ncbi_table.setModel(self.proxy)
|
| 749 |
-
self.ncbi_table.resizeColumnsToContents()
|
| 750 |
-
self.comboBox.addItems(["{0}".format(col) for col in self.model._df.columns])
|
| 751 |
-
self.activateWindow()
|
| 752 |
-
|
| 753 |
-
#close loading gif
|
| 754 |
-
self.loading_window.hide()
|
| 755 |
-
self.loading_window.loading_bar.setValue(0)
|
| 756 |
-
QtCore.QCoreApplication.processEvents()
|
| 757 |
-
except Exception as e:
|
| 758 |
-
logger.critical("Error in query_db() in ncbi tool.")
|
| 759 |
-
logger.critical(e)
|
| 760 |
-
logger.critical(traceback.format_exc())
|
| 761 |
-
msgBox = QtWidgets.QMessageBox()
|
| 762 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 763 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 764 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 765 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 766 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 767 |
-
msgBox.exec()
|
| 768 |
-
|
| 769 |
-
|
| 770 |
-
exit(-1)
|
| 771 |
-
|
| 772 |
-
@QtCore.pyqtSlot(int)
|
| 773 |
-
def on_view_horizontalHeader_sectionClicked(self, logicalIndex):
|
| 774 |
-
try:
|
| 775 |
-
self.logicalIndex = logicalIndex
|
| 776 |
-
self.menuValues = QtWidgets.QMenu(self)
|
| 777 |
-
self.signalMapper = QtCore.QSignalMapper(self)
|
| 778 |
-
self.comboBox.blockSignals(True)
|
| 779 |
-
self.comboBox.setCurrentIndex(logicalIndex)
|
| 780 |
-
self.comboBox.blockSignals(True)
|
| 781 |
-
valuesUnique = self.model._df.iloc[:, logicalIndex].unique()
|
| 782 |
-
if logicalIndex == 0:
|
| 783 |
-
valuesUnique = ['Sort: 0-9', 'Sort: 9-0']
|
| 784 |
-
elif logicalIndex == 2:
|
| 785 |
-
valuesUnique = ['Exclude N/A', 'Only N/A', 'Sort: A-Z', 'Sort: Z-A']
|
| 786 |
-
elif logicalIndex == 3:
|
| 787 |
-
valuesUnique = ['Sort: A-Z', 'Sort: Z-A']
|
| 788 |
-
elif logicalIndex == 4 or logicalIndex == 5:
|
| 789 |
-
valuesUnique = ['Exclude N/A', 'Only N/A', 'Sort: A-Z', 'Sort: Z-A']
|
| 790 |
-
|
| 791 |
-
actionAll = QtWidgets.QAction("All", self)
|
| 792 |
-
actionAll.triggered.connect(self.on_actionAll_triggered)
|
| 793 |
-
self.menuValues.addAction(actionAll)
|
| 794 |
-
self.menuValues.addSeparator()
|
| 795 |
-
for actionNumber, actionName in enumerate(sorted(list(set(valuesUnique)))):
|
| 796 |
-
action = QtWidgets.QAction(actionName, self)
|
| 797 |
-
self.signalMapper.setMapping(action, actionNumber)
|
| 798 |
-
action.triggered.connect(self.signalMapper.map)
|
| 799 |
-
self.menuValues.addAction(action)
|
| 800 |
-
self.signalMapper.mapped.connect(self.on_signalMapper_mapped)
|
| 801 |
-
headerPos = self.ncbi_table.mapToGlobal(self.horizontalHeader.pos())
|
| 802 |
-
posY = headerPos.y() + self.horizontalHeader.height()
|
| 803 |
-
posX = headerPos.x() + self.horizontalHeader.sectionViewportPosition(logicalIndex)
|
| 804 |
-
|
| 805 |
-
self.menuValues.exec_(QtCore.QPoint(posX, posY))
|
| 806 |
-
except Exception as e:
|
| 807 |
-
logger.critical("Error in on_view_horizontalHeader_sectionClicked() in ncbi tool.")
|
| 808 |
-
logger.critical(e)
|
| 809 |
-
logger.critical(traceback.format_exc())
|
| 810 |
-
msgBox = QtWidgets.QMessageBox()
|
| 811 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 812 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 813 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 814 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 815 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 816 |
-
msgBox.exec()
|
| 817 |
-
|
| 818 |
-
|
| 819 |
-
exit(-1)
|
| 820 |
-
|
| 821 |
-
@QtCore.pyqtSlot()
|
| 822 |
-
def on_actionAll_triggered(self):
|
| 823 |
-
try:
|
| 824 |
-
filterColumn = self.logicalIndex
|
| 825 |
-
self.proxy.setFilter("", filterColumn)
|
| 826 |
-
except Exception as e:
|
| 827 |
-
logger.critical("Error in on_actionAll_triggered() in ncbi tool.")
|
| 828 |
-
logger.critical(e)
|
| 829 |
-
logger.critical(traceback.format_exc())
|
| 830 |
-
msgBox = QtWidgets.QMessageBox()
|
| 831 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 832 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 833 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 834 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 835 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 836 |
-
msgBox.exec()
|
| 837 |
-
|
| 838 |
-
|
| 839 |
-
exit(-1)
|
| 840 |
-
|
| 841 |
-
@QtCore.pyqtSlot(int)
|
| 842 |
-
def on_signalMapper_mapped(self, i):
|
| 843 |
-
try:
|
| 844 |
-
indices = self.ncbi_table.selectionModel().selectedRows()
|
| 845 |
-
#stringAction = self.signalMapper.mapping(i).text()
|
| 846 |
-
if self.logicalIndex == 0:
|
| 847 |
-
if i == 0:
|
| 848 |
-
self.model.sort(self.logicalIndex, QtCore.Qt.DescendingOrder)
|
| 849 |
-
else:
|
| 850 |
-
self.model.sort(self.logicalIndex, QtCore.Qt.AscendingOrder)
|
| 851 |
-
elif self.logicalIndex == 3:
|
| 852 |
-
if i == 0:
|
| 853 |
-
self.model.sort(self.logicalIndex, QtCore.Qt.DescendingOrder)
|
| 854 |
-
else:
|
| 855 |
-
self.model.sort(self.logicalIndex, QtCore.Qt.AscendingOrder)
|
| 856 |
-
elif self.logicalIndex == 2 or self.logicalIndex == 4 or self.logicalIndex == 5:
|
| 857 |
-
if i == 0:
|
| 858 |
-
stringAction = "(?!^N/A$)(^.*$)"
|
| 859 |
-
filterColumn = self.logicalIndex
|
| 860 |
-
self.proxy.setFilter(stringAction, filterColumn)
|
| 861 |
-
elif i == 1:
|
| 862 |
-
stringAction = "N/A"
|
| 863 |
-
filterColumn = self.logicalIndex
|
| 864 |
-
self.proxy.setFilter(stringAction, filterColumn)
|
| 865 |
-
elif i == 2:
|
| 866 |
-
self.model.sort(self.logicalIndex, QtCore.Qt.DescendingOrder)
|
| 867 |
-
else:
|
| 868 |
-
self.model.sort(self.logicalIndex, QtCore.Qt.AscendingOrder)
|
| 869 |
-
elif self.logicalIndex == 6:
|
| 870 |
-
stringAction = self.signalMapper.mapping(i).text()
|
| 871 |
-
filterColumn = self.logicalIndex
|
| 872 |
-
self.proxy.setFilter(stringAction, filterColumn)
|
| 873 |
-
except Exception as e:
|
| 874 |
-
logger.critical("Error in on_signalMapper_mapped() in ncbi tool.")
|
| 875 |
-
logger.critical(e)
|
| 876 |
-
logger.critical(traceback.format_exc())
|
| 877 |
-
msgBox = QtWidgets.QMessageBox()
|
| 878 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 879 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 880 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 881 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 882 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 883 |
-
msgBox.exec()
|
| 884 |
-
|
| 885 |
-
|
| 886 |
-
exit(-1)
|
| 887 |
-
|
| 888 |
-
@QtCore.pyqtSlot()
|
| 889 |
-
def download_files_wrapper(self):
|
| 890 |
-
try:
|
| 891 |
-
self.progressBar.setValue(0)
|
| 892 |
-
|
| 893 |
-
#make sure rows are present in table
|
| 894 |
-
if self.df.shape[0] == 0:
|
| 895 |
-
msgBox = QtWidgets.QMessageBox()
|
| 896 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 897 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 898 |
-
msgBox.setWindowTitle("No Query Results")
|
| 899 |
-
msgBox.setText("Please run an NCBI query to fill the table with results to choose from!")
|
| 900 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Ok)
|
| 901 |
-
msgBox.exec()
|
| 902 |
-
|
| 903 |
-
return
|
| 904 |
-
|
| 905 |
-
#make sure user has selected at least one row
|
| 906 |
-
indices = self.ncbi_table.selectionModel().selectedRows()
|
| 907 |
-
if len(indices) == 0:
|
| 908 |
-
msgBox = QtWidgets.QMessageBox()
|
| 909 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 910 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 911 |
-
msgBox.setWindowTitle("No Rows Selected")
|
| 912 |
-
msgBox.setText("Please select rows from the table!")
|
| 913 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Ok)
|
| 914 |
-
msgBox.exec()
|
| 915 |
-
|
| 916 |
-
return
|
| 917 |
-
|
| 918 |
-
|
| 919 |
-
threadCount = QtCore.QThreadPool.globalInstance().maxThreadCount() # Get thread count
|
| 920 |
-
if len(indices) > threadCount:
|
| 921 |
-
msgBox = QtWidgets.QMessageBox()
|
| 922 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 923 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 924 |
-
msgBox.setWindowTitle("Too Many Selections!")
|
| 925 |
-
msgBox.setText("You only have " + str(threadCount) + " threads avaiable to download with.\n\nPlease select " + str(threadCount) + " or fewer rows.")
|
| 926 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Ok)
|
| 927 |
-
|
| 928 |
-
msgBox.exec()
|
| 929 |
-
|
| 930 |
-
return
|
| 931 |
-
|
| 932 |
-
|
| 933 |
-
#make sure file type is selected
|
| 934 |
-
if self.gbff_checkbox.isChecked() == False and self.fna_checkbox.isChecked() == False:
|
| 935 |
-
msgBox = QtWidgets.QMessageBox()
|
| 936 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 937 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 938 |
-
msgBox.setWindowTitle("No File Type Selected")
|
| 939 |
-
msgBox.setText("No file type selected. Please select the file types you want to download!")
|
| 940 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Ok)
|
| 941 |
-
msgBox.exec()
|
| 942 |
-
|
| 943 |
-
return
|
| 944 |
-
|
| 945 |
-
self.download_files()
|
| 946 |
-
except Exception as e:
|
| 947 |
-
logger.critical("Error in download_files_wrapper() in ncbi tool.")
|
| 948 |
-
logger.critical(e)
|
| 949 |
-
logger.critical(traceback.format_exc())
|
| 950 |
-
msgBox = QtWidgets.QMessageBox()
|
| 951 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 952 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 953 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 954 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 955 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 956 |
-
msgBox.exec()
|
| 957 |
-
|
| 958 |
-
|
| 959 |
-
exit(-1)
|
| 960 |
-
|
| 961 |
-
### When a new thread is started, spawn a label and progress bar for that thread and add it to the form layout.
|
| 962 |
-
def on_thread_start(self, data):
|
| 963 |
-
id = data # This is the id for the thread
|
| 964 |
-
tmp_lbl = QtWidgets.QLabel()
|
| 965 |
-
tmp_lbl.setText("Download(s) Started...")
|
| 966 |
-
tmp_bar = QtWidgets.QProgressBar()
|
| 967 |
-
self.labels[id] = tmp_lbl # Append thread label to list
|
| 968 |
-
self.progressbars[id] = tmp_bar # Append thread label to list
|
| 969 |
-
self.formLayout.addRow(tmp_lbl,tmp_bar) # Add label and bar to form layout
|
| 970 |
-
|
| 971 |
-
### When a thread is finished, update its label and progressbar for the last time
|
| 972 |
-
def on_thread_finish(self,data):
|
| 973 |
-
id = data[0]
|
| 974 |
-
my_bool = data[1]
|
| 975 |
-
if my_bool: # If thread finished succesfully
|
| 976 |
-
self.progressbars[id].setValue(int(self.progressbars[id].maximum())) #Make sure progress bar is full
|
| 977 |
-
self.labels[id].setText("Download(s) Complete!") #Make sure progress bar is full
|
| 978 |
-
self.progressBar.setValue(int(self.progressBar.value()+1)) # Increment overall progress bar when a thread finishes
|
| 979 |
-
QtWidgets.QApplication.processEvents() # Allow the progress bar to update
|
| 980 |
-
else:
|
| 981 |
-
self.progressBar.setMaximum(int(self.progressBar.maximum()-1)) # Subtract 1 from progress bar to reflect failed thread.
|
| 982 |
-
msgBox = QtWidgets.QMessageBox()
|
| 983 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 984 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 985 |
-
msgBox.setWindowTitle("Link Failed!")
|
| 986 |
-
msgBox.setText("Failed to find a valid link for ID: " + str(id) + ". Please make sure this ID is available in the selected database.")
|
| 987 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Ok)
|
| 988 |
-
msgBox.exec()
|
| 989 |
-
return
|
| 990 |
-
|
| 991 |
-
|
| 992 |
-
### When a file download starts, update the label and progress bar
|
| 993 |
-
def on_file_start(self, data):
|
| 994 |
-
id = data[0] # This is the id for the thread
|
| 995 |
-
prompt = data[1] # This is the prompt to set the label to
|
| 996 |
-
maxval = int(data[2]) # This is the file size
|
| 997 |
-
self.progressbars[id].setValue(0) # Set max value of progressbar
|
| 998 |
-
self.progressbars[id].setMaximum(int(maxval/1e3)) # Set max value of progressbar
|
| 999 |
-
|
| 1000 |
-
self.labels[id].setText(str(prompt)) # Set label text
|
| 1001 |
-
|
| 1002 |
-
## Taken from StackOverflow: https://stackoverflow.com/questions/57607072/update-pyqt-progress-from-another-thread-running-ftp-download
|
| 1003 |
-
def on_progress_ready(self, data):
|
| 1004 |
-
id = data[0] # This is the id for the thread
|
| 1005 |
-
val = int(data[1]) # This is the increment
|
| 1006 |
-
self.progressbars[id].setValue(int(self.progressbars[id].value() + val/1e3)) # Increment progress bar
|
| 1007 |
-
|
| 1008 |
-
### When a file download finishes, update the label and progress bar and add file name to list
|
| 1009 |
-
def on_file_finish(self,data):
|
| 1010 |
-
id = data[0] # This is the id for the thread
|
| 1011 |
-
prompt = data[1] # This is the prompt to set the label to
|
| 1012 |
-
file_name = data[2] # This is the filename
|
| 1013 |
-
self.progressbars[id].setValue(int(self.progressbars[id].maximum())) # Make sure progress bar is set to max after finishing download
|
| 1014 |
-
self.labels[id].setText(str(prompt))
|
| 1015 |
-
self.files.append(str(file_name)) # Add filename to list of downloaded files
|
| 1016 |
-
|
| 1017 |
-
def clean_bars(self):
|
| 1018 |
-
for key in self.progressbars:
|
| 1019 |
-
label = self.formLayout.labelForField(self.progressbars[key])
|
| 1020 |
-
if label is not None:
|
| 1021 |
-
label.deleteLater()
|
| 1022 |
-
self.progressbars[key].deleteLater()
|
| 1023 |
-
|
| 1024 |
-
self.labels.clear()
|
| 1025 |
-
self.progressbars.clear()
|
| 1026 |
-
self.threads.clear()
|
| 1027 |
-
def clear_layout(self):
|
| 1028 |
-
for i in reversed(range(self.formLayout.count())):
|
| 1029 |
-
self.formLayout.itemAt(i).widget().deleteLater()
|
| 1030 |
-
|
| 1031 |
-
## Taken from StackOverflow: https://stackoverflow.com/questions/57607072/update-pyqt-progress-from-another-thread-running-ftp-download
|
| 1032 |
-
def download_files(self):
|
| 1033 |
-
try:
|
| 1034 |
-
self.labels = {} # Key is the ID, value is the QLabel
|
| 1035 |
-
self.progressbars = {} # Key is the ID, value is the QProgressBar
|
| 1036 |
-
self.threads = {} # Key is the ID, value is the QThread
|
| 1037 |
-
indices = self.ncbi_table.selectionModel().selectedRows()
|
| 1038 |
-
len_ind = len(indices) # Get number of rows
|
| 1039 |
-
self.progressBar.setMaximum(int(len_ind)) # Set overall progress bar to be equal to number of rows being downloaded
|
| 1040 |
-
if len_ind == 0:
|
| 1041 |
-
return
|
| 1042 |
-
if self.genbank_checkbox.isChecked() == False and self.refseq_checkbox.isChecked() == False:
|
| 1043 |
-
return
|
| 1044 |
-
self.progressLabel.setText("Download(s) Started...") # Update progresslabel
|
| 1045 |
-
self.files = [] # Initialize list to hold downloaded files
|
| 1046 |
-
for index in indices: # For selected row(s) in table
|
| 1047 |
-
NewIndex = self.ncbi_table.model().index(index.row(), 0) # Get index of selected row
|
| 1048 |
-
id = self.ncbi_table.model().data(NewIndex) # Get ID from selected row
|
| 1049 |
-
dirs = [] # Initialize list to hold links to ftp directories
|
| 1050 |
-
if self.genbank_checkbox.isChecked():
|
| 1051 |
-
genbank_ftp = self.genbank_ftp_dict[int(id)]
|
| 1052 |
-
dirs.append(genbank_ftp)
|
| 1053 |
-
else:
|
| 1054 |
-
refseq_ftp = self.refseq_ftp_dict[int(id)]
|
| 1055 |
-
dirs.append(refseq_ftp)
|
| 1056 |
-
for dir in dirs: # Loop through the ftp links
|
| 1057 |
-
url = str(dir).replace('ftp://ftp.ncbi.nlm.nih.gov', '') # Create new link
|
| 1058 |
-
downloader = DownloadThread(parent=self,url=url,id=id) # Create a thread for the download
|
| 1059 |
-
downloader.started.connect(self.on_thread_start) # Connect signal to function
|
| 1060 |
-
downloader.finished.connect(self.on_thread_finish) # Connect signal to function
|
| 1061 |
-
downloader.file_started.connect(self.on_file_start)
|
| 1062 |
-
downloader.file_finished.connect(self.on_file_finish)
|
| 1063 |
-
downloader.data_progress.connect(self.on_progress_ready) # Connect signal to function
|
| 1064 |
-
self.threads[url] = downloader # Add thread to dictionary using the url as a key
|
| 1065 |
-
downloader.start()
|
| 1066 |
-
""" Make sure all threads are done before checking to see if files were downloaded """
|
| 1067 |
-
while len([self.threads[t] for t in self.threads if self.threads[t].isRunning()]) > 0:
|
| 1068 |
-
time.sleep(0.1)
|
| 1069 |
-
QtWidgets.QApplication.processEvents()
|
| 1070 |
-
self.progressBar.setValue(int(self.progressBar.maximum())) # Set progressBar to maximum
|
| 1071 |
-
self.progressLabel.setText("Download(s) Complete!") # Set progressBar to maximum
|
| 1072 |
-
|
| 1073 |
-
self.clean_bars() # Clear out all the bars now that downloading is done
|
| 1074 |
-
|
| 1075 |
-
for i in range(len(self.files)):
|
| 1076 |
-
self.files[i] = self.files[i].replace('.gz', '')
|
| 1077 |
-
if platform.system() == 'Windows':
|
| 1078 |
-
self.files[i] = self.files[i][self.files[i].rfind("\\")+1:]
|
| 1079 |
-
else:
|
| 1080 |
-
self.files[i] = self.files[i][self.files[i].rfind("/") + 1:]
|
| 1081 |
-
|
| 1082 |
-
if len(self.files) > 0:
|
| 1083 |
-
self.rename_files(self.files)
|
| 1084 |
-
else:
|
| 1085 |
-
self.clear_layout()
|
| 1086 |
-
self.clean_bars() # Clear out all the bars since the download failed
|
| 1087 |
-
msgBox = QtWidgets.QMessageBox()
|
| 1088 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 1089 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 1090 |
-
msgBox.setWindowTitle("No Files Downloaded")
|
| 1091 |
-
msgBox.setText("No files were downloaded from the selected NCBI files. Please make sure the selected files are available in the database selected.")
|
| 1092 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Ok)
|
| 1093 |
-
msgBox.exec()
|
| 1094 |
-
return
|
| 1095 |
-
|
| 1096 |
-
except Exception as e:
|
| 1097 |
-
logger.critical("Error in download_files() in ncbi tool.")
|
| 1098 |
-
logger.critical(e)
|
| 1099 |
-
logger.critical(traceback.format_exc())
|
| 1100 |
-
msgBox = QtWidgets.QMessageBox()
|
| 1101 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 1102 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 1103 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 1104 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 1105 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 1106 |
-
msgBox.exec()
|
| 1107 |
-
|
| 1108 |
-
|
| 1109 |
-
exit(-1)
|
| 1110 |
-
|
| 1111 |
-
@QtCore.pyqtSlot()
|
| 1112 |
-
def select_all(self):
|
| 1113 |
-
try:
|
| 1114 |
-
if self.all_rows.isChecked():
|
| 1115 |
-
self.ncbi_table.selectAll()
|
| 1116 |
-
else:
|
| 1117 |
-
self.ncbi_table.clearSelection()
|
| 1118 |
-
except Exception as e:
|
| 1119 |
-
logger.critical("Error in select_all() in ncbi tool.")
|
| 1120 |
-
logger.critical(e)
|
| 1121 |
-
logger.critical(traceback.format_exc())
|
| 1122 |
-
msgBox = QtWidgets.QMessageBox()
|
| 1123 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 1124 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 1125 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 1126 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 1127 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 1128 |
-
msgBox.exec()
|
| 1129 |
-
|
| 1130 |
-
|
| 1131 |
-
exit(-1)
|
| 1132 |
-
|
| 1133 |
-
def rename_files(self, files):
|
| 1134 |
-
try:
|
| 1135 |
-
msgBox = QtWidgets.QMessageBox()
|
| 1136 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 1137 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Question)
|
| 1138 |
-
msgBox.setWindowTitle("Rename Files")
|
| 1139 |
-
msgBox.setText("Would you like to rename the downloaded files?")
|
| 1140 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Yes)
|
| 1141 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.No)
|
| 1142 |
-
msgBox.exec()
|
| 1143 |
-
|
| 1144 |
-
if msgBox.result() == QtWidgets.QMessageBox.Yes:
|
| 1145 |
-
self.rename_window.rename_table.setRowCount(len(files))
|
| 1146 |
-
cnt = 0
|
| 1147 |
-
for file in files:
|
| 1148 |
-
item = QtWidgets.QTableWidgetItem(file)
|
| 1149 |
-
item.setFlags(QtCore.Qt.ItemIsEnabled)
|
| 1150 |
-
self.rename_window.rename_table.setItem(cnt, 0, item)
|
| 1151 |
-
|
| 1152 |
-
self.rename_window.rename_table.setCellWidget(cnt, 1, QtWidgets.QLineEdit())
|
| 1153 |
-
cnt += 1
|
| 1154 |
-
|
| 1155 |
-
header = self.rename_window.rename_table.horizontalHeader()
|
| 1156 |
-
self.rename_window.rename_table.resizeColumnsToContents()
|
| 1157 |
-
header.setSectionResizeMode(0, QtWidgets.QHeaderView.ResizeToContents)
|
| 1158 |
-
header.setSectionResizeMode(1, QtWidgets.QHeaderView.Stretch)
|
| 1159 |
-
self.rename_window.centerUI()
|
| 1160 |
-
self.rename_window.show()
|
| 1161 |
-
self.rename_window.activateWindow()
|
| 1162 |
-
else:
|
| 1163 |
-
GlobalSettings.mainWindow.fill_annotation_dropdown()
|
| 1164 |
-
self.goToPrompt.show()
|
| 1165 |
-
self.goToPrompt.activateWindow()
|
| 1166 |
-
except Exception as e:
|
| 1167 |
-
logger.critical("Error in rename_files() in ncbi tool.")
|
| 1168 |
-
logger.critical(e)
|
| 1169 |
-
logger.critical(traceback.format_exc())
|
| 1170 |
-
msgBox = QtWidgets.QMessageBox()
|
| 1171 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 1172 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 1173 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 1174 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 1175 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 1176 |
-
msgBox.exec()
|
| 1177 |
-
|
| 1178 |
-
|
| 1179 |
-
exit(-1)
|
| 1180 |
-
|
| 1181 |
-
def rename_go_back(self):
|
| 1182 |
-
try:
|
| 1183 |
-
self.rename_window.close()
|
| 1184 |
-
except Exception as e:
|
| 1185 |
-
logger.critical("Error in rename_go_back() in ncbi tool.")
|
| 1186 |
-
logger.critical(e)
|
| 1187 |
-
logger.critical(traceback.format_exc())
|
| 1188 |
-
msgBox = QtWidgets.QMessageBox()
|
| 1189 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 1190 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 1191 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 1192 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 1193 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 1194 |
-
msgBox.exec()
|
| 1195 |
-
exit(-1)
|
| 1196 |
-
|
| 1197 |
-
def submit_rename(self):
|
| 1198 |
-
try:
|
| 1199 |
-
#loop through columns and rename the files
|
| 1200 |
-
for row in range(self.rename_window.rename_table.rowCount()):
|
| 1201 |
-
orig = str(self.rename_window.rename_table.item(row, 0).text())
|
| 1202 |
-
new = str(self.rename_window.rename_table.cellWidget(row, 1).text())
|
| 1203 |
-
if new != "":
|
| 1204 |
-
if orig.find(".gbff")!= -1:
|
| 1205 |
-
if new.find(".") != -1:
|
| 1206 |
-
new = new[:new.find(".")]
|
| 1207 |
-
new = new + ".gbff"
|
| 1208 |
-
elif orig.find(".fna") != -1:
|
| 1209 |
-
if new.find(".") != -1:
|
| 1210 |
-
new = new[:new.find(".")]
|
| 1211 |
-
new = new + ".fna"
|
| 1212 |
-
|
| 1213 |
-
if platform.system() == "Windows":
|
| 1214 |
-
if new.find(".gbff") != -1:
|
| 1215 |
-
if os.path.isfile(GlobalSettings.CSPR_DB + "\\GBFF\\" + new) == False:
|
| 1216 |
-
os.rename(GlobalSettings.CSPR_DB + "\\GBFF\\" + orig, GlobalSettings.CSPR_DB + "\\GBFF\\" + new)
|
| 1217 |
-
else:
|
| 1218 |
-
msgBox = QtWidgets.QMessageBox()
|
| 1219 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 1220 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 1221 |
-
msgBox.setWindowTitle("Renaming Error")
|
| 1222 |
-
msgBox.setText("The filename: " + str(new) + " already exists. Please use a different name." )
|
| 1223 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Ok)
|
| 1224 |
-
msgBox.exec()
|
| 1225 |
-
return
|
| 1226 |
-
else:
|
| 1227 |
-
if os.path.isfile(GlobalSettings.CSPR_DB + "\\FNA\\" + new) == False:
|
| 1228 |
-
os.rename(GlobalSettings.CSPR_DB + "\\FNA\\" + orig, GlobalSettings.CSPR_DB + "\\FNA\\" + new)
|
| 1229 |
-
else:
|
| 1230 |
-
msgBox = QtWidgets.QMessageBox()
|
| 1231 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 1232 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 1233 |
-
msgBox.setWindowTitle("Renaming Error")
|
| 1234 |
-
msgBox.setText("The filename: " + str(new) + " already exists. Please use a different name." )
|
| 1235 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Ok)
|
| 1236 |
-
msgBox.exec()
|
| 1237 |
-
return
|
| 1238 |
-
|
| 1239 |
-
else:
|
| 1240 |
-
#unix cannot have spaces in paths
|
| 1241 |
-
new = new.replace(" ","")
|
| 1242 |
-
if new.find(".gbff") != -1:
|
| 1243 |
-
if os.path.isfile(GlobalSettings.CSPR_DB + "/GBFF/" + new) == False:
|
| 1244 |
-
os.rename(GlobalSettings.CSPR_DB + "/GBFF/" + orig, GlobalSettings.CSPR_DB + "/GBFF/" + new)
|
| 1245 |
-
else:
|
| 1246 |
-
msgBox = QtWidgets.QMessageBox()
|
| 1247 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 1248 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 1249 |
-
msgBox.setWindowTitle("Renaming Error")
|
| 1250 |
-
msgBox.setText(
|
| 1251 |
-
"The filename: " + str(new) + " already exists. Please use a different name.")
|
| 1252 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Ok)
|
| 1253 |
-
msgBox.exec()
|
| 1254 |
-
return
|
| 1255 |
-
else:
|
| 1256 |
-
if os.path.isfile(GlobalSettings.CSPR_DB + "/FNA/" + new) == False:
|
| 1257 |
-
os.rename(GlobalSettings.CSPR_DB + "/FNA/" + orig, GlobalSettings.CSPR_DB + "/FNA/" + new)
|
| 1258 |
-
else:
|
| 1259 |
-
msgBox = QtWidgets.QMessageBox()
|
| 1260 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 1261 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 1262 |
-
msgBox.setWindowTitle("Renaming Error")
|
| 1263 |
-
msgBox.setText(
|
| 1264 |
-
"The filename: " + str(new) + " already exists. Please use a different name.")
|
| 1265 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Ok)
|
| 1266 |
-
msgBox.exec()
|
| 1267 |
-
return
|
| 1268 |
-
|
| 1269 |
-
self.rename_window.rename_table.setRowCount(0)
|
| 1270 |
-
self.rename_window.close()
|
| 1271 |
-
GlobalSettings.mainWindow.fill_annotation_dropdown()
|
| 1272 |
-
self.goToPrompt.centerUI()
|
| 1273 |
-
self.goToPrompt.show()
|
| 1274 |
-
self.goToPrompt.activateWindow()
|
| 1275 |
-
except Exception as e:
|
| 1276 |
-
logger.critical("Error in submit_rename() in ncbi tool.")
|
| 1277 |
-
logger.critical(e)
|
| 1278 |
-
logger.critical(traceback.format_exc())
|
| 1279 |
-
msgBox = QtWidgets.QMessageBox()
|
| 1280 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 1281 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 1282 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 1283 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 1284 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 1285 |
-
msgBox.exec()
|
| 1286 |
-
|
| 1287 |
-
|
| 1288 |
-
exit(-1)
|
| 1289 |
-
|
| 1290 |
-
def stay(self):
|
| 1291 |
-
try:
|
| 1292 |
-
self.goToPrompt.hide()
|
| 1293 |
-
except Exception as e:
|
| 1294 |
-
logger.critical("Error in stay() in ncbi tool.")
|
| 1295 |
-
logger.critical(e)
|
| 1296 |
-
logger.critical(traceback.format_exc())
|
| 1297 |
-
msgBox = QtWidgets.QMessageBox()
|
| 1298 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 1299 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 1300 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 1301 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 1302 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 1303 |
-
msgBox.exec()
|
| 1304 |
-
|
| 1305 |
-
|
| 1306 |
-
exit(-1)
|
| 1307 |
-
|
| 1308 |
-
def close(self):
|
| 1309 |
-
try:
|
| 1310 |
-
self.hide()
|
| 1311 |
-
self.goToPrompt.hide()
|
| 1312 |
-
except Exception as e:
|
| 1313 |
-
logger.critical("Error in close() in ncbi tool.")
|
| 1314 |
-
logger.critical(e)
|
| 1315 |
-
logger.critical(traceback.format_exc())
|
| 1316 |
-
msgBox = QtWidgets.QMessageBox()
|
| 1317 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 1318 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 1319 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 1320 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 1321 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 1322 |
-
msgBox.exec()
|
| 1323 |
-
|
| 1324 |
-
|
| 1325 |
-
exit(-1)
|
| 1326 |
-
|
| 1327 |
-
|
| 1328 |
-
class goToPrompt(QtWidgets.QMainWindow):
|
| 1329 |
-
def __init__(self):
|
| 1330 |
-
try:
|
| 1331 |
-
super(goToPrompt, self).__init__()
|
| 1332 |
-
uic.loadUi(GlobalSettings.appdir + 'ncbi_nav_page.ui', self)
|
| 1333 |
-
self.setWindowTitle("Navigate")
|
| 1334 |
-
self.setWindowIcon(Qt.QIcon(GlobalSettings.appdir + "cas9image.ico"))
|
| 1335 |
-
self.label.setText("Successfully downloaded file(s) to the CASPERdb directory:\n" + GlobalSettings.CSPR_DB)
|
| 1336 |
-
self.label.setAlignment(QtCore.Qt.AlignCenter)
|
| 1337 |
-
groupbox_style = """
|
| 1338 |
-
QGroupBox:title{subcontrol-origin: margin;
|
| 1339 |
-
left: 10px;
|
| 1340 |
-
padding: 0 5px 0 5px;}
|
| 1341 |
-
QGroupBox#groupBox{border: 2px solid rgb(111,181,110);
|
| 1342 |
-
border-radius: 9px;
|
| 1343 |
-
font: bold 14pt 'Arial';
|
| 1344 |
-
margin-top: 10px;}"""
|
| 1345 |
-
self.groupBox.setStyleSheet(groupbox_style)
|
| 1346 |
-
|
| 1347 |
-
self.scaleUI()
|
| 1348 |
-
except Exception as e:
|
| 1349 |
-
logger.critical("Error initializing goToPrompt class in ncbi tool.")
|
| 1350 |
-
logger.critical(e)
|
| 1351 |
-
logger.critical(traceback.format_exc())
|
| 1352 |
-
msgBox = QtWidgets.QMessageBox()
|
| 1353 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 1354 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 1355 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 1356 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 1357 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 1358 |
-
msgBox.exec()
|
| 1359 |
-
|
| 1360 |
-
|
| 1361 |
-
exit(-1)
|
| 1362 |
-
|
| 1363 |
-
#scale UI based on current screen
|
| 1364 |
-
def scaleUI(self):
|
| 1365 |
-
try:
|
| 1366 |
-
self.repaint()
|
| 1367 |
-
QtWidgets.QApplication.processEvents()
|
| 1368 |
-
|
| 1369 |
-
screen = self.screen()
|
| 1370 |
-
dpi = screen.physicalDotsPerInch()
|
| 1371 |
-
width = screen.geometry().width()
|
| 1372 |
-
height = screen.geometry().height()
|
| 1373 |
-
|
| 1374 |
-
# font scaling
|
| 1375 |
-
fontSize = 12
|
| 1376 |
-
self.centralWidget().setStyleSheet("font: " + str(fontSize) + "pt 'Arial';")
|
| 1377 |
-
|
| 1378 |
-
self.adjustSize()
|
| 1379 |
-
|
| 1380 |
-
currentWidth = self.size().width()
|
| 1381 |
-
currentHeight = self.size().height()
|
| 1382 |
-
|
| 1383 |
-
# window scaling
|
| 1384 |
-
# 1920x1080 => 550x200
|
| 1385 |
-
scaledWidth = int((width * 575) / 1920)
|
| 1386 |
-
scaledHeight = int((height * 225) / 1080)
|
| 1387 |
-
|
| 1388 |
-
if scaledHeight < currentHeight:
|
| 1389 |
-
scaledHeight = currentHeight
|
| 1390 |
-
if scaledWidth < currentWidth:
|
| 1391 |
-
scaledWidth = currentWidth
|
| 1392 |
-
|
| 1393 |
-
screen = QtWidgets.QApplication.desktop().screenNumber(QtWidgets.QApplication.desktop().cursor().pos())
|
| 1394 |
-
centerPoint = QtWidgets.QApplication.desktop().screenGeometry(screen).center()
|
| 1395 |
-
x = centerPoint.x()
|
| 1396 |
-
y = centerPoint.y()
|
| 1397 |
-
x = x - (math.ceil(scaledWidth / 2))
|
| 1398 |
-
y = y - (math.ceil(scaledHeight / 2))
|
| 1399 |
-
self.setGeometry(x, y, scaledWidth, scaledHeight)
|
| 1400 |
-
|
| 1401 |
-
self.repaint()
|
| 1402 |
-
QtWidgets.QApplication.processEvents()
|
| 1403 |
-
|
| 1404 |
-
except Exception as e:
|
| 1405 |
-
logger.critical("Error in scaleUI() in goToPrompt in NCBI tool.")
|
| 1406 |
-
logger.critical(e)
|
| 1407 |
-
logger.critical(traceback.format_exc())
|
| 1408 |
-
msgBox = QtWidgets.QMessageBox()
|
| 1409 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 1410 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 1411 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 1412 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 1413 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 1414 |
-
msgBox.exec()
|
| 1415 |
-
|
| 1416 |
-
|
| 1417 |
-
exit(-1)
|
| 1418 |
-
|
| 1419 |
-
#center UI on current screen
|
| 1420 |
-
def centerUI(self):
|
| 1421 |
-
try:
|
| 1422 |
-
self.repaint()
|
| 1423 |
-
QtWidgets.QApplication.processEvents()
|
| 1424 |
-
|
| 1425 |
-
# center window on current screen
|
| 1426 |
-
width = self.width()
|
| 1427 |
-
height = self.height()
|
| 1428 |
-
screen = QtWidgets.QApplication.desktop().screenNumber(QtWidgets.QApplication.desktop().cursor().pos())
|
| 1429 |
-
centerPoint = QtWidgets.QApplication.desktop().screenGeometry(screen).center()
|
| 1430 |
-
x = centerPoint.x()
|
| 1431 |
-
y = centerPoint.y()
|
| 1432 |
-
x = x - (math.ceil(width / 2))
|
| 1433 |
-
y = y - (math.ceil(height / 2))
|
| 1434 |
-
self.setGeometry(x, y, width, height)
|
| 1435 |
-
|
| 1436 |
-
self.repaint()
|
| 1437 |
-
QtWidgets.QApplication.processEvents()
|
| 1438 |
-
except Exception as e:
|
| 1439 |
-
logger.critical("Error in centerUI() in goToPrompt in NCBI tool.")
|
| 1440 |
-
logger.critical(e)
|
| 1441 |
-
logger.critical(traceback.format_exc())
|
| 1442 |
-
msgBox = QtWidgets.QMessageBox()
|
| 1443 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 1444 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 1445 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 1446 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 1447 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 1448 |
-
msgBox.exec()
|
| 1449 |
-
|
| 1450 |
-
|
| 1451 |
-
exit(-1)
|
| 1452 |
-
|
| 1453 |
-
|
| 1454 |
-
class rename_window(QtWidgets.QMainWindow):
|
| 1455 |
-
def __init__(self):
|
| 1456 |
-
try:
|
| 1457 |
-
super(rename_window, self).__init__()
|
| 1458 |
-
uic.loadUi(GlobalSettings.appdir + "ncbi_rename_window.ui", self)
|
| 1459 |
-
self.setWindowIcon(Qt.QIcon(GlobalSettings.appdir + "cas9image.ico"))
|
| 1460 |
-
self.setWindowTitle("Rename Files")
|
| 1461 |
-
self.rename_table.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.AdjustToContents)
|
| 1462 |
-
self.rename_table.setColumnCount(2)
|
| 1463 |
-
self.rename_table.setHorizontalHeaderLabels(['Original Filename', 'New Filename'])
|
| 1464 |
-
|
| 1465 |
-
self.scaleUI()
|
| 1466 |
-
except Exception as e:
|
| 1467 |
-
logger.critical("Error initializing rename_window class in ncbi tool.")
|
| 1468 |
-
logger.critical(e)
|
| 1469 |
-
logger.critical(traceback.format_exc())
|
| 1470 |
-
msgBox = QtWidgets.QMessageBox()
|
| 1471 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 1472 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 1473 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 1474 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 1475 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 1476 |
-
msgBox.exec()
|
| 1477 |
-
|
| 1478 |
-
|
| 1479 |
-
exit(-1)
|
| 1480 |
-
|
| 1481 |
-
#scale UI based on current screen
|
| 1482 |
-
def scaleUI(self):
|
| 1483 |
-
try:
|
| 1484 |
-
self.repaint()
|
| 1485 |
-
QtWidgets.QApplication.processEvents()
|
| 1486 |
-
|
| 1487 |
-
screen = self.screen()
|
| 1488 |
-
dpi = screen.physicalDotsPerInch()
|
| 1489 |
-
width = screen.geometry().width()
|
| 1490 |
-
height = screen.geometry().height()
|
| 1491 |
-
|
| 1492 |
-
# font scaling
|
| 1493 |
-
fontSize = 12
|
| 1494 |
-
self.centralWidget().setStyleSheet("font: " + str(fontSize) + "pt 'Arial';")
|
| 1495 |
-
|
| 1496 |
-
self.adjustSize()
|
| 1497 |
-
|
| 1498 |
-
currentWidth = self.size().width()
|
| 1499 |
-
currentHeight = self.size().height()
|
| 1500 |
-
|
| 1501 |
-
# window scaling
|
| 1502 |
-
# 1920x1080 => 550x200
|
| 1503 |
-
scaledWidth = int((width * 575) / 1920)
|
| 1504 |
-
scaledHeight = int((height * 300) / 1080)
|
| 1505 |
-
|
| 1506 |
-
if scaledHeight < currentHeight:
|
| 1507 |
-
scaledHeight = currentHeight
|
| 1508 |
-
if scaledWidth < currentWidth:
|
| 1509 |
-
scaledWidth = currentWidth
|
| 1510 |
-
|
| 1511 |
-
screen = QtWidgets.QApplication.desktop().screenNumber(QtWidgets.QApplication.desktop().cursor().pos())
|
| 1512 |
-
centerPoint = QtWidgets.QApplication.desktop().screenGeometry(screen).center()
|
| 1513 |
-
x = centerPoint.x()
|
| 1514 |
-
y = centerPoint.y()
|
| 1515 |
-
x = x - (math.ceil(scaledWidth / 2))
|
| 1516 |
-
y = y - (math.ceil(scaledHeight / 2))
|
| 1517 |
-
self.setGeometry(x, y, scaledWidth, scaledHeight)
|
| 1518 |
-
|
| 1519 |
-
self.repaint()
|
| 1520 |
-
QtWidgets.QApplication.processEvents()
|
| 1521 |
-
|
| 1522 |
-
except Exception as e:
|
| 1523 |
-
logger.critical("Error in scaleUI() in rename window in NCBI tool.")
|
| 1524 |
-
logger.critical(e)
|
| 1525 |
-
logger.critical(traceback.format_exc())
|
| 1526 |
-
msgBox = QtWidgets.QMessageBox()
|
| 1527 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 1528 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 1529 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 1530 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 1531 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 1532 |
-
msgBox.exec()
|
| 1533 |
-
|
| 1534 |
-
|
| 1535 |
-
exit(-1)
|
| 1536 |
-
|
| 1537 |
-
#center UI on current screen
|
| 1538 |
-
def centerUI(self):
|
| 1539 |
-
try:
|
| 1540 |
-
self.repaint()
|
| 1541 |
-
QtWidgets.QApplication.processEvents()
|
| 1542 |
-
|
| 1543 |
-
# center window on current screen
|
| 1544 |
-
width = self.width()
|
| 1545 |
-
height = self.height()
|
| 1546 |
-
screen = QtWidgets.QApplication.desktop().screenNumber(QtWidgets.QApplication.desktop().cursor().pos())
|
| 1547 |
-
centerPoint = QtWidgets.QApplication.desktop().screenGeometry(screen).center()
|
| 1548 |
-
x = centerPoint.x()
|
| 1549 |
-
y = centerPoint.y()
|
| 1550 |
-
x = x - (math.ceil(width / 2))
|
| 1551 |
-
y = y - (math.ceil(height / 2))
|
| 1552 |
-
self.setGeometry(x, y, width, height)
|
| 1553 |
-
|
| 1554 |
-
self.repaint()
|
| 1555 |
-
QtWidgets.QApplication.processEvents()
|
| 1556 |
-
except Exception as e:
|
| 1557 |
-
logger.critical("Error in centerUI() in rename window in NCBI tool.")
|
| 1558 |
-
logger.critical(e)
|
| 1559 |
-
logger.critical(traceback.format_exc())
|
| 1560 |
-
msgBox = QtWidgets.QMessageBox()
|
| 1561 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 1562 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 1563 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 1564 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 1565 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 1566 |
-
msgBox.exec()
|
| 1567 |
-
|
| 1568 |
-
|
| 1569 |
-
exit(-1)
|
| 1570 |
-
|
| 1571 |
-
|
| 1572 |
-
#loading window UI class for when data is loading
|
| 1573 |
-
class loading_window(QtWidgets.QMainWindow):
|
| 1574 |
-
def __init__(self):
|
| 1575 |
-
try:
|
| 1576 |
-
super(loading_window, self).__init__()
|
| 1577 |
-
uic.loadUi(GlobalSettings.appdir + "loading_data_form.ui", self)
|
| 1578 |
-
self.loading_bar.setValue(0)
|
| 1579 |
-
self.setWindowTitle("Loading NCBI Data")
|
| 1580 |
-
self.setWindowIcon(Qt.QIcon(GlobalSettings.appdir + "cas9image.ico"))
|
| 1581 |
-
self.scaleUI()
|
| 1582 |
-
except Exception as e:
|
| 1583 |
-
logger.critical("Error initializing loading_window class in ncbi tool.")
|
| 1584 |
-
logger.critical(e)
|
| 1585 |
-
logger.critical(traceback.format_exc())
|
| 1586 |
-
msgBox = QtWidgets.QMessageBox()
|
| 1587 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 1588 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 1589 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 1590 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 1591 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 1592 |
-
msgBox.exec()
|
| 1593 |
-
|
| 1594 |
-
|
| 1595 |
-
exit(-1)
|
| 1596 |
-
|
| 1597 |
-
#scale UI based on current screen
|
| 1598 |
-
def scaleUI(self):
|
| 1599 |
-
try:
|
| 1600 |
-
self.repaint()
|
| 1601 |
-
QtWidgets.QApplication.processEvents()
|
| 1602 |
-
|
| 1603 |
-
screen = self.screen()
|
| 1604 |
-
dpi = screen.physicalDotsPerInch()
|
| 1605 |
-
width = screen.geometry().width()
|
| 1606 |
-
height = screen.geometry().height()
|
| 1607 |
-
|
| 1608 |
-
# font scaling
|
| 1609 |
-
fontSize = 12
|
| 1610 |
-
self.centralWidget().setStyleSheet("font: " + str(fontSize) + "pt 'Arial';")
|
| 1611 |
-
|
| 1612 |
-
self.adjustSize()
|
| 1613 |
-
|
| 1614 |
-
currentWidth = self.size().width()
|
| 1615 |
-
currentHeight = self.size().height()
|
| 1616 |
-
|
| 1617 |
-
# scale/center window
|
| 1618 |
-
scaledWidth = int((width * 450) / 1920)
|
| 1619 |
-
scaledHeight = int((height * 125) / 1080)
|
| 1620 |
-
|
| 1621 |
-
if scaledHeight < currentHeight:
|
| 1622 |
-
scaledHeight = currentHeight
|
| 1623 |
-
if scaledWidth < currentWidth:
|
| 1624 |
-
scaledWidth = currentWidth
|
| 1625 |
-
|
| 1626 |
-
screen = QtWidgets.QApplication.desktop().screenNumber(QtWidgets.QApplication.desktop().cursor().pos())
|
| 1627 |
-
centerPoint = QtWidgets.QApplication.desktop().screenGeometry(screen).center()
|
| 1628 |
-
x = centerPoint.x()
|
| 1629 |
-
y = centerPoint.y()
|
| 1630 |
-
x = x - (math.ceil(scaledWidth / 2))
|
| 1631 |
-
y = y - (math.ceil(scaledHeight / 2))
|
| 1632 |
-
self.setGeometry(x, y, scaledWidth, scaledHeight)
|
| 1633 |
-
|
| 1634 |
-
self.repaint()
|
| 1635 |
-
QtWidgets.QApplication.processEvents()
|
| 1636 |
-
except Exception as e:
|
| 1637 |
-
logger.critical("Error in scaleUI() in loading_window() class in ncbi tool.")
|
| 1638 |
-
logger.critical(e)
|
| 1639 |
-
logger.critical(traceback.format_exc())
|
| 1640 |
-
msgBox = QtWidgets.QMessageBox()
|
| 1641 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 1642 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 1643 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 1644 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 1645 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 1646 |
-
msgBox.exec()
|
| 1647 |
-
|
| 1648 |
-
|
| 1649 |
-
exit(-1)
|
| 1650 |
-
|
| 1651 |
-
#center UI on current screen
|
| 1652 |
-
def centerUI(self):
|
| 1653 |
-
try:
|
| 1654 |
-
self.repaint()
|
| 1655 |
-
QtWidgets.QApplication.processEvents()
|
| 1656 |
-
|
| 1657 |
-
width = self.width()
|
| 1658 |
-
height = self.height()
|
| 1659 |
-
#scale/center window
|
| 1660 |
-
screen = QtWidgets.QApplication.desktop().screenNumber(QtWidgets.QApplication.desktop().cursor().pos())
|
| 1661 |
-
centerPoint = QtWidgets.QApplication.desktop().screenGeometry(screen).center()
|
| 1662 |
-
x = centerPoint.x()
|
| 1663 |
-
y = centerPoint.y()
|
| 1664 |
-
x = x - (math.ceil(width / 2))
|
| 1665 |
-
y = y - (math.ceil(height / 2))
|
| 1666 |
-
self.setGeometry(x, y, width, height)
|
| 1667 |
-
|
| 1668 |
-
self.repaint()
|
| 1669 |
-
QtWidgets.QApplication.processEvents()
|
| 1670 |
-
except Exception as e:
|
| 1671 |
-
logger.critical("Error in centerUI() in loading_window() class in ncbi tool.")
|
| 1672 |
-
logger.critical(e)
|
| 1673 |
-
logger.critical(traceback.format_exc())
|
| 1674 |
-
msgBox = QtWidgets.QMessageBox()
|
| 1675 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 1676 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 1677 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 1678 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 1679 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 1680 |
-
msgBox.exec()
|
| 1681 |
-
|
| 1682 |
-
|
| 1683 |
-
exit(-1)
|
| 1684 |
-
|
| 1685 |
-
|
| 1686 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -3,7 +3,7 @@
|
|
| 3 |
To interpret these run the class instance at the bottom of the file with the desired base64 representation into the
|
| 4 |
decompress_tuple function."""
|
| 5 |
from PyQt5 import QtWidgets, Qt, uic, QtCore, QtGui
|
| 6 |
-
import GlobalSettings
|
| 7 |
|
| 8 |
# Takes a QtTableWidget and returns a list of headers
|
| 9 |
def get_table_headers(table):
|
|
|
|
| 3 |
To interpret these run the class instance at the bottom of the file with the desired base64 representation into the
|
| 4 |
decompress_tuple function."""
|
| 5 |
from PyQt5 import QtWidgets, Qt, uic, QtCore, QtGui
|
| 6 |
+
import models.GlobalSettings as GlobalSettings
|
| 7 |
|
| 8 |
# Takes a QtTableWidget and returns a list of headers
|
| 9 |
def get_table_headers(table):
|
|
@@ -1,11 +1,41 @@
|
|
| 1 |
from PyQt5 import QtWidgets, QtGui, QtCore
|
|
|
|
| 2 |
import math
|
| 3 |
-
|
| 4 |
-
import GlobalSettings
|
| 5 |
|
| 6 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 7 |
try:
|
| 8 |
-
|
| 9 |
window.repaint()
|
| 10 |
QtWidgets.QApplication.processEvents()
|
| 11 |
|
|
@@ -15,11 +45,16 @@ def scale_ui(window, base_width=1920, base_height=1080, font_size=12, header_fon
|
|
| 15 |
|
| 16 |
# Font scaling
|
| 17 |
window.centralWidget().setStyleSheet(f"font: {font_size}pt 'Arial';")
|
| 18 |
-
window
|
|
|
|
| 19 |
|
| 20 |
# Header scaling
|
| 21 |
-
if hasattr(window, 'label_8'):
|
| 22 |
-
window.label_8.setStyleSheet(f"font: bold {header_font_size}pt 'Arial';")
|
|
|
|
|
|
|
|
|
|
|
|
|
| 23 |
|
| 24 |
window.adjustSize()
|
| 25 |
|
|
@@ -31,8 +66,8 @@ def scale_ui(window, base_width=1920, base_height=1080, font_size=12, header_fon
|
|
| 31 |
window.logo.setPixmap(QtGui.QPixmap(GlobalSettings.appdir + "assets/CASPER-logo.jpg"))
|
| 32 |
|
| 33 |
# Window resize and center
|
| 34 |
-
scaledWidth = int((width * 1150) / base_width)
|
| 35 |
-
scaledHeight = int((height * 650) / base_height)
|
| 36 |
|
| 37 |
if scaledHeight < currentHeight:
|
| 38 |
scaledHeight = currentHeight
|
|
@@ -74,6 +109,5 @@ def center_ui(window):
|
|
| 74 |
window.setGeometry(x, y, width, height)
|
| 75 |
window.repaint()
|
| 76 |
except Exception as e:
|
| 77 |
-
# Log the error or handle it as needed
|
| 78 |
print(f"Error centering window: {e}")
|
| 79 |
|
|
|
|
| 1 |
from PyQt5 import QtWidgets, QtGui, QtCore
|
| 2 |
+
import traceback
|
| 3 |
import math
|
| 4 |
+
import models.GlobalSettings as GlobalSettings
|
|
|
|
| 5 |
|
| 6 |
+
logger = GlobalSettings.logger
|
| 7 |
+
|
| 8 |
+
def show_message(fontSize, icon, title, message, button=QtWidgets.QMessageBox.StandardButton.Close):
|
| 9 |
+
try:
|
| 10 |
+
msgBox = QtWidgets.QMessageBox()
|
| 11 |
+
msgBox.setStyleSheet(f"font: {fontSize}pt 'Arial'")
|
| 12 |
+
msgBox.setIcon(icon)
|
| 13 |
+
msgBox.setWindowTitle(title)
|
| 14 |
+
msgBox.setText(message)
|
| 15 |
+
msgBox.addButton(button)
|
| 16 |
+
msgBox.exec()
|
| 17 |
+
except Exception as e:
|
| 18 |
+
print(e)
|
| 19 |
+
|
| 20 |
+
def show_error(message, e):
|
| 21 |
+
try:
|
| 22 |
+
logger.critical(message)
|
| 23 |
+
logger.critical(e)
|
| 24 |
+
logger.critical(traceback.format_exc())
|
| 25 |
+
|
| 26 |
+
show_message(
|
| 27 |
+
fontSize=12,
|
| 28 |
+
icon=QtWidgets.QMessageBox.Icon.Critical,
|
| 29 |
+
title="Fatal Error",
|
| 30 |
+
message=f"Fatal Error:\n{str(e)}\n\nFor more information on this error, look at CASPER.log in the application folder."
|
| 31 |
+
)
|
| 32 |
+
except Exception as e:
|
| 33 |
+
print(e)
|
| 34 |
+
|
| 35 |
+
exit(-1)
|
| 36 |
+
|
| 37 |
+
def scale_ui(window, base_width=1920, base_height=1080, font_size=12, header_font_size=30, custom_scale_width=None, custom_scale_height=None):
|
| 38 |
try:
|
|
|
|
| 39 |
window.repaint()
|
| 40 |
QtWidgets.QApplication.processEvents()
|
| 41 |
|
|
|
|
| 45 |
|
| 46 |
# Font scaling
|
| 47 |
window.centralWidget().setStyleSheet(f"font: {font_size}pt 'Arial';")
|
| 48 |
+
if hasattr(window, 'menuBar'):
|
| 49 |
+
window.menuBar().setStyleSheet(f"font: {font_size}pt 'Arial';")
|
| 50 |
|
| 51 |
# Header scaling
|
| 52 |
+
# if hasattr(window, 'label_8'):
|
| 53 |
+
# window.label_8.setStyleSheet(f"font: bold {header_font_size}pt 'Arial';")
|
| 54 |
+
|
| 55 |
+
if hasattr(window, 'title'):
|
| 56 |
+
scaled_title_font_size = int(header_font_size * (width / base_width))
|
| 57 |
+
window.title.setStyleSheet(f"font: bold {scaled_title_font_size}pt 'Arial';")
|
| 58 |
|
| 59 |
window.adjustSize()
|
| 60 |
|
|
|
|
| 66 |
window.logo.setPixmap(QtGui.QPixmap(GlobalSettings.appdir + "assets/CASPER-logo.jpg"))
|
| 67 |
|
| 68 |
# Window resize and center
|
| 69 |
+
scaledWidth = int((width * (custom_scale_width if custom_scale_width else 1150)) / base_width)
|
| 70 |
+
scaledHeight = int((height * (custom_scale_height if custom_scale_height else 650)) / base_height)
|
| 71 |
|
| 72 |
if scaledHeight < currentHeight:
|
| 73 |
scaledHeight = currentHeight
|
|
|
|
| 109 |
window.setGeometry(x, y, width, height)
|
| 110 |
window.repaint()
|
| 111 |
except Exception as e:
|
|
|
|
| 112 |
print(f"Error centering window: {e}")
|
| 113 |
|
|
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import webbrowser
|
| 2 |
+
from utils.ui import show_error
|
| 3 |
+
|
| 4 |
+
def ncbi_blast_page():
|
| 5 |
+
open_webpage("https://blast.ncbi.nlm.nih.gov/Blast.cgi")
|
| 6 |
+
|
| 7 |
+
def ncbi_page():
|
| 8 |
+
open_webpage("https://www.ncbi.nlm.nih.gov/")
|
| 9 |
+
|
| 10 |
+
def repo_page():
|
| 11 |
+
open_webpage("https://github.com/TrinhLab/CASPERapp")
|
| 12 |
+
|
| 13 |
+
def open_webpage(url):
|
| 14 |
+
try:
|
| 15 |
+
webbrowser.open(url, new=2)
|
| 16 |
+
except Exception as e:
|
| 17 |
+
show_error("Error in open_webpage()", e)
|
|
@@ -1,17 +1,15 @@
|
|
| 1 |
###############################################################################
|
| 2 |
-
# This is the Annotation Parser File
|
| 3 |
# INPUTS: inputs are the annotation files to parse. Currently, only gbff is supported.
|
| 4 |
# OUTPUTS: the outputs are data structures that store the parsed data
|
| 5 |
################################################################################
|
| 6 |
|
| 7 |
from PyQt5 import QtWidgets
|
| 8 |
import gffutils
|
| 9 |
-
import GlobalSettings
|
| 10 |
import os
|
| 11 |
from Bio import SeqIO
|
| 12 |
import traceback
|
| 13 |
|
| 14 |
-
#global logger
|
| 15 |
logger = GlobalSettings.logger
|
| 16 |
|
| 17 |
class Annotation_Parser:
|
|
@@ -94,9 +92,6 @@ class Annotation_Parser:
|
|
| 94 |
|
| 95 |
exit(-1)
|
| 96 |
|
| 97 |
-
|
| 98 |
-
|
| 99 |
-
|
| 100 |
### The workhorse function of AnnotationParser, this searches the annotation file for the user's search and returns features matching the description.
|
| 101 |
def genbank_search(self, queries, same_search):
|
| 102 |
index_number = 0
|
|
|
|
| 1 |
###############################################################################
|
|
|
|
| 2 |
# INPUTS: inputs are the annotation files to parse. Currently, only gbff is supported.
|
| 3 |
# OUTPUTS: the outputs are data structures that store the parsed data
|
| 4 |
################################################################################
|
| 5 |
|
| 6 |
from PyQt5 import QtWidgets
|
| 7 |
import gffutils
|
| 8 |
+
import models.GlobalSettings as GlobalSettings
|
| 9 |
import os
|
| 10 |
from Bio import SeqIO
|
| 11 |
import traceback
|
| 12 |
|
|
|
|
| 13 |
logger = GlobalSettings.logger
|
| 14 |
|
| 15 |
class Annotation_Parser:
|
|
|
|
| 92 |
|
| 93 |
exit(-1)
|
| 94 |
|
|
|
|
|
|
|
|
|
|
| 95 |
### The workhorse function of AnnotationParser, this searches the annotation file for the user's search and returns features matching the description.
|
| 96 |
def genbank_search(self, queries, same_search):
|
| 97 |
index_number = 0
|
|
@@ -0,0 +1,125 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import models.GlobalSettings as GlobalSettings
|
| 2 |
+
from utils.ui import show_error, scale_ui, center_ui
|
| 3 |
+
from PyQt5 import QtWidgets, QtCore, uic, Qt
|
| 4 |
+
from views.annotation_functions import *
|
| 5 |
+
import traceback
|
| 6 |
+
|
| 7 |
+
logger = GlobalSettings.logger
|
| 8 |
+
|
| 9 |
+
class AnnotationWindow(QtWidgets.QMainWindow):
|
| 10 |
+
def __init__(self, info_path):
|
| 11 |
+
super(AnnotationWindow, self).__init__()
|
| 12 |
+
uic.loadUi(GlobalSettings.appdir + 'ui/annotation_details.ui', self)
|
| 13 |
+
self.setWindowIcon(Qt.QIcon(GlobalSettings.appdir + "cas9image.ico"))
|
| 14 |
+
self.Submit_button.clicked.connect(self.submit)
|
| 15 |
+
self.Go_Back_Button.clicked.connect(self.go_Back)
|
| 16 |
+
self.select_all_checkbox.stateChanged.connect(self.select_all_genes)
|
| 17 |
+
self.fontSize = 12
|
| 18 |
+
self.mainWindow = ""
|
| 19 |
+
self.type = ""
|
| 20 |
+
self.mwfg = self.frameGeometry() ##Center window
|
| 21 |
+
self.cp = QtWidgets.QDesktopWidget().availableGeometry().center() ##Center window
|
| 22 |
+
self.switcher_table = [1, 1, 1, 1, 1, 1, 1, 1]
|
| 23 |
+
self.tableWidget.setHorizontalScrollMode(QtWidgets.QAbstractItemView.ScrollPerPixel)
|
| 24 |
+
self.tableWidget.setVerticalScrollMode(QtWidgets.QAbstractItemView.ScrollPerPixel)
|
| 25 |
+
self.tableWidget.setSelectionMode(QtWidgets.QAbstractItemView.MultiSelection)
|
| 26 |
+
self.tableWidget.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
|
| 27 |
+
self.tableWidget.setAutoScroll(False)
|
| 28 |
+
self.tableWidget.horizontalHeader().sectionClicked.connect(self.table_sorting)
|
| 29 |
+
|
| 30 |
+
scale_ui(self, custom_scale_width=1150, custom_scale_height=650)
|
| 31 |
+
|
| 32 |
+
def table_sorting(self, logicalIndex):
|
| 33 |
+
try:
|
| 34 |
+
self.switcher_table[logicalIndex] *= -1
|
| 35 |
+
order = QtCore.Qt.DescendingOrder if self.switcher_table[logicalIndex] == -1 else QtCore.Qt.AscendingOrder
|
| 36 |
+
self.tableWidget.sortItems(logicalIndex, order)
|
| 37 |
+
except Exception as e:
|
| 38 |
+
show_error("table_sorting() in Annotation Window", e)
|
| 39 |
+
|
| 40 |
+
#submit selected rows for results to process
|
| 41 |
+
def submit(self):
|
| 42 |
+
try:
|
| 43 |
+
self.mainWindow.collect_table_data_nonkegg()
|
| 44 |
+
self.mainWindow.show() # Open main window back up
|
| 45 |
+
except Exception as e:
|
| 46 |
+
logger.critical("Error in submit() in AnnotationWindow.")
|
| 47 |
+
logger.critical(e)
|
| 48 |
+
logger.critical(traceback.format_exc())
|
| 49 |
+
show_error("submit() in AnnotationWindow", e)
|
| 50 |
+
finally:
|
| 51 |
+
self.hide() # Close annotation window regardless of success or failure
|
| 52 |
+
|
| 53 |
+
#go back to main
|
| 54 |
+
def go_Back(self):
|
| 55 |
+
try:
|
| 56 |
+
self.tableWidget.clear()
|
| 57 |
+
self.mainWindow.searches.clear()
|
| 58 |
+
self.tableWidget.setColumnCount(0)
|
| 59 |
+
self.mainWindow.show()
|
| 60 |
+
self.mainWindow.progressBar.setValue(0)
|
| 61 |
+
self.hide()
|
| 62 |
+
except Exception as e:
|
| 63 |
+
show_error("go_Back() in AnnotationWindow", e)
|
| 64 |
+
self.mainWindow.checkBoxes.clear()
|
| 65 |
+
|
| 66 |
+
# this is the connection for the select all checkbox - selects/deselects all the genes in the table
|
| 67 |
+
# this function is very similar to the other fill_table, it just works with the other types of annotation files
|
| 68 |
+
def fill_table_nonKegg(self, mainWindow, results_list):
|
| 69 |
+
try:
|
| 70 |
+
self.tableWidget.clearContents()
|
| 71 |
+
self.mainWindow = mainWindow
|
| 72 |
+
self.tableWidget.setColumnCount(5)
|
| 73 |
+
self.mainWindow.progressBar.setValue(85)
|
| 74 |
+
self.tableWidget.setHorizontalHeaderLabels(["Feature Type", "Chromosome/Scaffold #", "Feature ID/Locus Tag", "Feature Name", "Feature Description"])
|
| 75 |
+
|
| 76 |
+
mainWindow.checkBoxes = []
|
| 77 |
+
self.type = "nonkegg"
|
| 78 |
+
|
| 79 |
+
for index, result in enumerate(results_list[:1000]): # Limit to first 1000 results
|
| 80 |
+
self.tableWidget.setRowCount(index + 1) # Increment table row count
|
| 81 |
+
chrom, feature = result
|
| 82 |
+
|
| 83 |
+
# Create and set table items
|
| 84 |
+
items = [
|
| 85 |
+
QtWidgets.QTableWidgetItem(feature.type),
|
| 86 |
+
QtWidgets.QTableWidgetItem(str(chrom)),
|
| 87 |
+
QtWidgets.QTableWidgetItem(get_id(feature)),
|
| 88 |
+
QtWidgets.QTableWidgetItem(get_name(feature)),
|
| 89 |
+
QtWidgets.QTableWidgetItem(get_description(feature))
|
| 90 |
+
]
|
| 91 |
+
|
| 92 |
+
for col, item in enumerate(items):
|
| 93 |
+
self.tableWidget.setItem(index, col, item)
|
| 94 |
+
|
| 95 |
+
mainWindow.checkBoxes.append((chrom, feature, index))
|
| 96 |
+
|
| 97 |
+
self.tableWidget.resizeColumnsToContents()
|
| 98 |
+
mainWindow.hide()
|
| 99 |
+
|
| 100 |
+
#center on current screen
|
| 101 |
+
center_ui(self)
|
| 102 |
+
self.show()
|
| 103 |
+
self.activateWindow()
|
| 104 |
+
|
| 105 |
+
return 0
|
| 106 |
+
except Exception as e:
|
| 107 |
+
show_error("fill_table_nonKegg() in AnnotationWindow", e)
|
| 108 |
+
|
| 109 |
+
# this is the connection for the select all checkbox - selects/deselects all the genes in the table
|
| 110 |
+
def select_all_genes(self):
|
| 111 |
+
try:
|
| 112 |
+
if self.select_all_checkbox.isChecked():
|
| 113 |
+
self.tableWidget.selectAll()
|
| 114 |
+
else:
|
| 115 |
+
self.tableWidget.clearSelection()
|
| 116 |
+
except Exception as e:
|
| 117 |
+
show_error("select_all_genes() in AnnotationWindow", e)
|
| 118 |
+
|
| 119 |
+
# this function calls the closingWindow class.
|
| 120 |
+
def closeEvent(self, event):
|
| 121 |
+
try:
|
| 122 |
+
GlobalSettings.mainWindow.closeFunction()
|
| 123 |
+
except Exception as e:
|
| 124 |
+
show_error("closeEvent() in AnnotationWindow", e)
|
| 125 |
+
event.accept()
|
|
@@ -1,170 +1,35 @@
|
|
| 1 |
-
from Algorithms import get_table_headers
|
| 2 |
-
import sys
|
| 3 |
-
import os
|
| 4 |
-
import io
|
| 5 |
-
from PyQt5 import QtWidgets, Qt, QtGui, QtCore, uic
|
| 6 |
-
from CoTargeting import CoTargeting
|
| 7 |
-
from closingWin import closingWindow
|
| 8 |
-
from Results import Results
|
| 9 |
-
from NewGenome import NewGenome
|
| 10 |
-
from NewEndonuclease import NewEndonuclease
|
| 11 |
-
import genomeBrowser
|
| 12 |
-
import webbrowser
|
| 13 |
-
import requests
|
| 14 |
-
import GlobalSettings
|
| 15 |
-
import multitargeting
|
| 16 |
-
from AnnotationParser import Annotation_Parser
|
| 17 |
-
from export_tool import export_tool
|
| 18 |
-
from generateLib import genLibrary
|
| 19 |
-
from CSPRparser import CSPRparser
|
| 20 |
-
import populationAnalysis
|
| 21 |
import platform
|
| 22 |
-
import ncbi
|
|
|
|
|
|
|
|
|
|
| 23 |
import glob
|
| 24 |
import traceback
|
| 25 |
-
import
|
| 26 |
-
import
|
| 27 |
-
from
|
| 28 |
-
from
|
| 29 |
-
from
|
| 30 |
-
from
|
| 31 |
-
|
| 32 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 33 |
logger = GlobalSettings.logger
|
| 34 |
|
| 35 |
fontSize = 12
|
| 36 |
|
| 37 |
-
#Annotation file and search query from MainWindow
|
| 38 |
-
class AnnotationsWindow(QtWidgets.QMainWindow):
|
| 39 |
-
#init annotation window class
|
| 40 |
-
def __init__(self, info_path):
|
| 41 |
-
super(AnnotationsWindow, self).__init__()
|
| 42 |
-
uic.loadUi(GlobalSettings.appdir + 'annotation_details.ui', self)
|
| 43 |
-
self.setWindowIcon(Qt.QIcon(GlobalSettings.appdir + "cas9image.ico"))
|
| 44 |
-
self.Submit_button.clicked.connect(self.submit)
|
| 45 |
-
self.Go_Back_Button.clicked.connect(self.go_Back)
|
| 46 |
-
self.select_all_checkbox.stateChanged.connect(self.select_all_genes)
|
| 47 |
-
self.fontSize = 12 # Initialize fontSize
|
| 48 |
-
self.mainWindow = ""
|
| 49 |
-
self.type = ""
|
| 50 |
-
self.mwfg = self.frameGeometry() ##Center window
|
| 51 |
-
self.cp = QtWidgets.QDesktopWidget().availableGeometry().center() ##Center window
|
| 52 |
-
self.switcher_table = [1, 1, 1, 1, 1, 1, 1, 1]
|
| 53 |
-
self.tableWidget.setHorizontalScrollMode(QtWidgets.QAbstractItemView.ScrollPerPixel)
|
| 54 |
-
self.tableWidget.setVerticalScrollMode(QtWidgets.QAbstractItemView.ScrollPerPixel)
|
| 55 |
-
self.tableWidget.setSelectionMode(QtWidgets.QAbstractItemView.MultiSelection)
|
| 56 |
-
self.tableWidget.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
|
| 57 |
-
self.tableWidget.setAutoScroll(False)
|
| 58 |
-
self.tableWidget.horizontalHeader().sectionClicked.connect(self.table_sorting)
|
| 59 |
-
|
| 60 |
-
scale_ui(self)
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
def table_sorting(self, logicalIndex):
|
| 64 |
-
try:
|
| 65 |
-
self.switcher_table[logicalIndex] *= -1
|
| 66 |
-
order = QtCore.Qt.DescendingOrder if self.switcher_table[logicalIndex] == -1 else QtCore.Qt.AscendingOrder
|
| 67 |
-
self.tableWidget.sortItems(logicalIndex, order)
|
| 68 |
-
except Exception as e:
|
| 69 |
-
show_error("table_sorting() in Annotation Window", e)
|
| 70 |
-
|
| 71 |
-
#submit selected rows for results to process
|
| 72 |
-
def submit(self):
|
| 73 |
-
try:
|
| 74 |
-
self.mainWindow.collect_table_data_nonkegg()
|
| 75 |
-
self.mainWindow.show() # Open main window back up
|
| 76 |
-
except Exception as e:
|
| 77 |
-
logger.critical("Error in submit() in AnnotationsWindow.")
|
| 78 |
-
logger.critical(e)
|
| 79 |
-
logger.critical(traceback.format_exc())
|
| 80 |
-
show_error("submit() in AnnotationsWindow", e)
|
| 81 |
-
finally:
|
| 82 |
-
self.hide() # Close annotation window regardless of success or failure
|
| 83 |
-
|
| 84 |
-
#go back to main
|
| 85 |
-
def go_Back(self):
|
| 86 |
-
try:
|
| 87 |
-
self.tableWidget.clear()
|
| 88 |
-
self.mainWindow.searches.clear()
|
| 89 |
-
self.tableWidget.setColumnCount(0)
|
| 90 |
-
self.mainWindow.show()
|
| 91 |
-
self.mainWindow.progressBar.setValue(0)
|
| 92 |
-
self.hide()
|
| 93 |
-
except Exception as e:
|
| 94 |
-
show_error("go_Back() in AnnotationsWindow", e)
|
| 95 |
-
self.mainWindow.checkBoxes.clear()
|
| 96 |
-
|
| 97 |
-
# this is the connection for the select all checkbox - selects/deselects all the genes in the table
|
| 98 |
-
# this function is very similar to the other fill_table, it just works with the other types of annotation files
|
| 99 |
-
def fill_table_nonKegg(self, mainWindow, results_list):
|
| 100 |
-
try:
|
| 101 |
-
self.tableWidget.clearContents()
|
| 102 |
-
self.mainWindow = mainWindow
|
| 103 |
-
self.tableWidget.setColumnCount(5)
|
| 104 |
-
self.mainWindow.progressBar.setValue(85)
|
| 105 |
-
self.tableWidget.setHorizontalHeaderLabels(["Feature Type", "Chromosome/Scaffold #", "Feature ID/Locus Tag", "Feature Name", "Feature Description"])
|
| 106 |
-
|
| 107 |
-
mainWindow.checkBoxes = []
|
| 108 |
-
self.type = "nonkegg"
|
| 109 |
-
|
| 110 |
-
for index, result in enumerate(results_list[:1000]): # Limit to first 1000 results
|
| 111 |
-
self.tableWidget.setRowCount(index + 1) # Increment table row count
|
| 112 |
-
chrom, feature = result
|
| 113 |
-
|
| 114 |
-
# Create and set table items
|
| 115 |
-
items = [
|
| 116 |
-
QtWidgets.QTableWidgetItem(feature.type),
|
| 117 |
-
QtWidgets.QTableWidgetItem(str(chrom)),
|
| 118 |
-
QtWidgets.QTableWidgetItem(get_id(feature)),
|
| 119 |
-
QtWidgets.QTableWidgetItem(get_name(feature)),
|
| 120 |
-
QtWidgets.QTableWidgetItem(get_description(feature))
|
| 121 |
-
]
|
| 122 |
-
|
| 123 |
-
for col, item in enumerate(items):
|
| 124 |
-
self.tableWidget.setItem(index, col, item)
|
| 125 |
-
|
| 126 |
-
mainWindow.checkBoxes.append((chrom, feature, index))
|
| 127 |
-
|
| 128 |
-
self.tableWidget.resizeColumnsToContents()
|
| 129 |
-
mainWindow.hide()
|
| 130 |
-
|
| 131 |
-
#center on current screen
|
| 132 |
-
center_ui(self)
|
| 133 |
-
self.show()
|
| 134 |
-
self.activateWindow()
|
| 135 |
-
|
| 136 |
-
return 0
|
| 137 |
-
except Exception as e:
|
| 138 |
-
show_error("fill_table_nonKegg() in AnnotationsWindow", e)
|
| 139 |
-
|
| 140 |
-
# this is the connection for the select all checkbox - selects/deselects all the genes in the table
|
| 141 |
-
def select_all_genes(self):
|
| 142 |
-
try:
|
| 143 |
-
if self.select_all_checkbox.isChecked():
|
| 144 |
-
self.tableWidget.selectAll()
|
| 145 |
-
else:
|
| 146 |
-
self.tableWidget.clearSelection()
|
| 147 |
-
except Exception as e:
|
| 148 |
-
show_error("select_all_genes() in AnnotationsWindow", e)
|
| 149 |
-
|
| 150 |
-
# this function calls the closingWindow class.
|
| 151 |
-
def closeEvent(self, event):
|
| 152 |
-
try:
|
| 153 |
-
GlobalSettings.mainWindow.closeFunction()
|
| 154 |
-
except Exception as e:
|
| 155 |
-
show_error("closeEvent() in AnnotationsWindow", e)
|
| 156 |
-
event.accept()
|
| 157 |
-
|
| 158 |
-
# =========================================================================================
|
| 159 |
-
# CLASS NAME: CMainWindow
|
| 160 |
-
# Inputs: Takes in the path information from the startup window and also all input parameters
|
| 161 |
-
# Outputs: The results of the target search process by generating a new Results window
|
| 162 |
-
# =========================================================================================
|
| 163 |
class CMainWindow(QtWidgets.QMainWindow):
|
| 164 |
-
|
| 165 |
def __init__(self, info_path):
|
| 166 |
super(CMainWindow, self).__init__()
|
| 167 |
-
uic.loadUi(GlobalSettings.appdir + 'CASPER_main.ui', self)
|
| 168 |
self.dbpath = ""
|
| 169 |
self.inputstring = "" # This is the search string
|
| 170 |
self.info_path = info_path
|
|
@@ -220,18 +85,18 @@ class CMainWindow(QtWidgets.QMainWindow):
|
|
| 220 |
""" Connect functions to actions (menu bar) """
|
| 221 |
self.actionOpen_Genome_Browser.triggered.connect(self.launch_newGenomeBrowser)
|
| 222 |
self.actionExit.triggered.connect(self.close_app)
|
| 223 |
-
self.visit_repo.triggered.connect(
|
| 224 |
self.actionChange_Directory.triggered.connect(self.change_directory)
|
| 225 |
-
self.actionNCBI.triggered.connect(
|
| 226 |
# self.actionCasper2.triggered.connect(self.open_casper2_web_page)
|
| 227 |
-
self.actionNCBI_BLAST.triggered.connect(
|
| 228 |
|
| 229 |
|
| 230 |
|
| 231 |
self.progressBar.setMinimum(0)
|
| 232 |
self.progressBar.setMaximum(100)
|
| 233 |
self.progressBar.reset()
|
| 234 |
-
self.Annotation_Window =
|
| 235 |
self.geneEntryField.setPlaceholderText("Example Inputs: \n\n"
|
| 236 |
"Option 1: Feature (ID, Locus Tag, or Name)\n"
|
| 237 |
"Example: 854068/YOL086C/ADH1 for S. cerevisiae alcohol dehydrogenase 1\n\n"
|
|
@@ -256,9 +121,8 @@ class CMainWindow(QtWidgets.QMainWindow):
|
|
| 256 |
self.genomebrowser = genomeBrowser.genomebrowser()
|
| 257 |
self.launch_ncbi_button.clicked.connect(self.launch_ncbi)
|
| 258 |
|
| 259 |
-
#scale UI
|
| 260 |
self.first_show = True
|
| 261 |
-
scale_ui(self)
|
| 262 |
|
| 263 |
# this function prepares everything for the generate library function
|
| 264 |
# it is very similar to the gather settings, how ever it stores the data instead of calling the Annotation Window class
|
|
@@ -341,21 +205,8 @@ class CMainWindow(QtWidgets.QMainWindow):
|
|
| 341 |
else:
|
| 342 |
self.progressBar.setValue(0)
|
| 343 |
except Exception as e:
|
| 344 |
-
|
| 345 |
-
|
| 346 |
-
logger.critical(traceback.format_exc())
|
| 347 |
-
|
| 348 |
-
#print("prep genlib")
|
| 349 |
-
msgBox = QtWidgets.QMessageBox()
|
| 350 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 351 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 352 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 353 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 354 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 355 |
-
msgBox.exec()
|
| 356 |
-
|
| 357 |
-
exit(-1)
|
| 358 |
-
|
| 359 |
# Function for collecting the settings from the input field and transferring them to run_results
|
| 360 |
def gather_settings(self):
|
| 361 |
try:
|
|
@@ -405,26 +256,8 @@ class CMainWindow(QtWidgets.QMainWindow):
|
|
| 405 |
sinput = self.inputstring
|
| 406 |
self.run_results("sequence", sinput, same_search)
|
| 407 |
except Exception as e:
|
| 408 |
-
|
| 409 |
-
|
| 410 |
-
logger.critical(traceback.format_exc())
|
| 411 |
-
msgBox = QtWidgets.QMessageBox()
|
| 412 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 413 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 414 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 415 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 416 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 417 |
-
msgBox.exec()
|
| 418 |
-
msgBox = QtWidgets.QMessageBox()
|
| 419 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 420 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 421 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 422 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 423 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 424 |
-
msgBox.exec()
|
| 425 |
-
|
| 426 |
-
exit(-1)
|
| 427 |
-
|
| 428 |
# ---- Following functions are for running the auxillary algorithms and windows ---- #
|
| 429 |
# this function is parses the annotation file given, and then goes through and goes onto results
|
| 430 |
# it will call other versions of collect_table_data and fill_table that work with these file types
|
|
@@ -746,19 +579,8 @@ class CMainWindow(QtWidgets.QMainWindow):
|
|
| 746 |
|
| 747 |
|
| 748 |
except Exception as e:
|
| 749 |
-
|
| 750 |
-
|
| 751 |
-
logger.critical(traceback.format_exc())
|
| 752 |
-
msgBox = QtWidgets.QMessageBox()
|
| 753 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 754 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 755 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 756 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 757 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 758 |
-
msgBox.exec()
|
| 759 |
-
|
| 760 |
-
exit(-1)
|
| 761 |
-
|
| 762 |
def handle_feature_search(self, input_string, open_anno_window):
|
| 763 |
file_type = self.annotation_parser.find_which_file_version()
|
| 764 |
if file_type == -1 or self.annotation_files.currentText() == "None":
|
|
@@ -778,26 +600,23 @@ class CMainWindow(QtWidgets.QMainWindow):
|
|
| 778 |
self.hide()
|
| 779 |
self.newGenome.show()
|
| 780 |
except Exception as e:
|
| 781 |
-
show_error("launch_newGenome() in main", e)
|
| 782 |
|
| 783 |
-
#launch new endo tool
|
| 784 |
def launch_newEndonuclease(self):
|
| 785 |
try:
|
| 786 |
-
|
| 787 |
-
self.newEndonuclease.centerUI()
|
| 788 |
self.newEndonuclease.show()
|
| 789 |
self.newEndonuclease.activateWindow()
|
| 790 |
except Exception as e:
|
| 791 |
-
show_error("launch_newEndonuclease() in main", e)
|
| 792 |
|
| 793 |
#launch genome browser tool
|
| 794 |
def launch_newGenomeBrowser(self):
|
| 795 |
try:
|
| 796 |
self.genomebrowser.createGraph(self)
|
| 797 |
except Exception as e:
|
| 798 |
-
show_error("launch_newGenomeBrowser() in main", e)
|
| 799 |
|
| 800 |
-
#launch ncbi tool
|
| 801 |
def launch_ncbi(self):
|
| 802 |
try:
|
| 803 |
msgBox = QtWidgets.QMessageBox()
|
|
@@ -811,7 +630,7 @@ class CMainWindow(QtWidgets.QMainWindow):
|
|
| 811 |
|
| 812 |
if self.ncbi.first_show:
|
| 813 |
self.ncbi.first_show = False
|
| 814 |
-
self.ncbi
|
| 815 |
|
| 816 |
self.ncbi.show()
|
| 817 |
self.ncbi.activateWindow()
|
|
@@ -859,19 +678,8 @@ class CMainWindow(QtWidgets.QMainWindow):
|
|
| 859 |
self.pushButton_ViewTargets.setEnabled(True)
|
| 860 |
self.GenerateLibrary.setEnabled(True)
|
| 861 |
except Exception as e:
|
| 862 |
-
|
| 863 |
-
|
| 864 |
-
logger.critical(traceback.format_exc())
|
| 865 |
-
msgBox = QtWidgets.QMessageBox()
|
| 866 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 867 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 868 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 869 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 870 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 871 |
-
msgBox.exec()
|
| 872 |
-
|
| 873 |
-
exit(-1)
|
| 874 |
-
|
| 875 |
def separate_line(self, input_string):
|
| 876 |
try:
|
| 877 |
export_array = []
|
|
@@ -886,19 +694,8 @@ class CMainWindow(QtWidgets.QMainWindow):
|
|
| 886 |
export_array.append(input_string[:index])
|
| 887 |
input_string = input_string[index + 1:]
|
| 888 |
except Exception as e:
|
| 889 |
-
|
| 890 |
-
|
| 891 |
-
logger.critical(traceback.format_exc())
|
| 892 |
-
msgBox = QtWidgets.QMessageBox()
|
| 893 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 894 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 895 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 896 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 897 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 898 |
-
msgBox.exec()
|
| 899 |
-
|
| 900 |
-
exit(-1)
|
| 901 |
-
|
| 902 |
def removeWhiteSpace(self, strng):
|
| 903 |
try:
|
| 904 |
while True:
|
|
@@ -910,18 +707,7 @@ class CMainWindow(QtWidgets.QMainWindow):
|
|
| 910 |
return strng
|
| 911 |
strng = strng[:len(strng) - 1]
|
| 912 |
except Exception as e:
|
| 913 |
-
|
| 914 |
-
logger.critical(e)
|
| 915 |
-
logger.critical(traceback.format_exc())
|
| 916 |
-
msgBox = QtWidgets.QMessageBox()
|
| 917 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 918 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 919 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 920 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 921 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 922 |
-
msgBox.exec()
|
| 923 |
-
|
| 924 |
-
exit(-1)
|
| 925 |
|
| 926 |
# Function to enable and disable the Annotation function if searching by position or sequence
|
| 927 |
def toggle_annotation(self):
|
|
@@ -931,18 +717,7 @@ class CMainWindow(QtWidgets.QMainWindow):
|
|
| 931 |
else:
|
| 932 |
self.Step2.setEnabled(True)
|
| 933 |
except Exception as e:
|
| 934 |
-
|
| 935 |
-
logger.critical(e)
|
| 936 |
-
logger.critical(traceback.format_exc())
|
| 937 |
-
msgBox = QtWidgets.QMessageBox()
|
| 938 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 939 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 940 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 941 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 942 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 943 |
-
msgBox.exec()
|
| 944 |
-
|
| 945 |
-
exit(-1)
|
| 946 |
|
| 947 |
def fill_annotation_dropdown(self):
|
| 948 |
try:
|
|
@@ -962,19 +737,8 @@ class CMainWindow(QtWidgets.QMainWindow):
|
|
| 962 |
self.annotation_files.addItems(annotation_files)
|
| 963 |
self.annotation_files.addItems(["None"])
|
| 964 |
except Exception as e:
|
| 965 |
-
|
| 966 |
-
|
| 967 |
-
logger.critical(traceback.format_exc())
|
| 968 |
-
msgBox = QtWidgets.QMessageBox()
|
| 969 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 970 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 971 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 972 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 973 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 974 |
-
msgBox.exec()
|
| 975 |
-
|
| 976 |
-
exit(-1)
|
| 977 |
-
|
| 978 |
def make_dictonary(self):
|
| 979 |
try:
|
| 980 |
url = "https://www.genome.jp/dbget-bin/get_linkdb?-t+genes+gn:" + self.TNumbers[
|
|
@@ -1009,18 +773,7 @@ class CMainWindow(QtWidgets.QMainWindow):
|
|
| 1009 |
self.gene_list[key] = [seq]
|
| 1010 |
z = 5
|
| 1011 |
except Exception as e:
|
| 1012 |
-
|
| 1013 |
-
logger.critical(e)
|
| 1014 |
-
logger.critical(traceback.format_exc())
|
| 1015 |
-
msgBox = QtWidgets.QMessageBox()
|
| 1016 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 1017 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 1018 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 1019 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 1020 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 1021 |
-
msgBox.exec()
|
| 1022 |
-
|
| 1023 |
-
exit(-1)
|
| 1024 |
|
| 1025 |
def organism_finder(self, long_str):
|
| 1026 |
try:
|
|
@@ -1032,18 +785,7 @@ class CMainWindow(QtWidgets.QMainWindow):
|
|
| 1032 |
index = index + 1
|
| 1033 |
return long_str[:semi - index]
|
| 1034 |
except Exception as e:
|
| 1035 |
-
|
| 1036 |
-
logger.critical(e)
|
| 1037 |
-
logger.critical(traceback.format_exc())
|
| 1038 |
-
msgBox = QtWidgets.QMessageBox()
|
| 1039 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 1040 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 1041 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 1042 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 1043 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 1044 |
-
msgBox.exec()
|
| 1045 |
-
|
| 1046 |
-
exit(-1)
|
| 1047 |
|
| 1048 |
# This method is for testing the execution of a button call to make sure the button is linked properly
|
| 1049 |
def testexe(self):
|
|
@@ -1064,19 +806,8 @@ class CMainWindow(QtWidgets.QMainWindow):
|
|
| 1064 |
else:
|
| 1065 |
pass
|
| 1066 |
except Exception as e:
|
| 1067 |
-
|
| 1068 |
-
|
| 1069 |
-
logger.critical(traceback.format_exc())
|
| 1070 |
-
msgBox = QtWidgets.QMessageBox()
|
| 1071 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 1072 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 1073 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 1074 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 1075 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 1076 |
-
msgBox.exec()
|
| 1077 |
-
|
| 1078 |
-
exit(-1)
|
| 1079 |
-
|
| 1080 |
def getData(self):
|
| 1081 |
try:
|
| 1082 |
try:
|
|
@@ -1129,18 +860,7 @@ class CMainWindow(QtWidgets.QMainWindow):
|
|
| 1129 |
self.endoChoice.addItems(self.organisms_to_endos[str(self.orgChoice.currentText())])
|
| 1130 |
self.orgChoice.currentIndexChanged.connect(self.changeEndos)
|
| 1131 |
except Exception as e:
|
| 1132 |
-
|
| 1133 |
-
logger.critical(e)
|
| 1134 |
-
logger.critical(traceback.format_exc())
|
| 1135 |
-
msgBox = QtWidgets.QMessageBox()
|
| 1136 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 1137 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 1138 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 1139 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 1140 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 1141 |
-
msgBox.exec()
|
| 1142 |
-
|
| 1143 |
-
exit(-1)
|
| 1144 |
|
| 1145 |
def changeEndos(self):
|
| 1146 |
try:
|
|
@@ -1158,18 +878,7 @@ class CMainWindow(QtWidgets.QMainWindow):
|
|
| 1158 |
self.radioButton_Gene.hide()
|
| 1159 |
self.radioButton_Position.hide()
|
| 1160 |
except Exception as e:
|
| 1161 |
-
|
| 1162 |
-
logger.critical(e)
|
| 1163 |
-
logger.critical(traceback.format_exc())
|
| 1164 |
-
msgBox = QtWidgets.QMessageBox()
|
| 1165 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 1166 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 1167 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 1168 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 1169 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 1170 |
-
msgBox.exec()
|
| 1171 |
-
|
| 1172 |
-
exit(-1)
|
| 1173 |
|
| 1174 |
def change_directory(self):
|
| 1175 |
try:
|
|
@@ -1206,7 +915,6 @@ class CMainWindow(QtWidgets.QMainWindow):
|
|
| 1206 |
except Exception as e:
|
| 1207 |
show_error("Error in change_directory() in main.", e)
|
| 1208 |
|
| 1209 |
-
#change to multi-targeting window
|
| 1210 |
def changeto_multitargeting(self):
|
| 1211 |
try:
|
| 1212 |
os.chdir(os.getcwd())
|
|
@@ -1218,41 +926,19 @@ class CMainWindow(QtWidgets.QMainWindow):
|
|
| 1218 |
GlobalSettings.mainWindow.hide()
|
| 1219 |
|
| 1220 |
except Exception as e:
|
| 1221 |
-
|
| 1222 |
-
logger.critical(e)
|
| 1223 |
-
logger.critical(traceback.format_exc())
|
| 1224 |
-
msgBox = QtWidgets.QMessageBox()
|
| 1225 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 1226 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 1227 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 1228 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 1229 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 1230 |
-
msgBox.exec()
|
| 1231 |
-
|
| 1232 |
-
exit(-1)
|
| 1233 |
|
| 1234 |
#change to population analysis window
|
| 1235 |
def changeto_population_Analysis(self):
|
| 1236 |
try:
|
| 1237 |
GlobalSettings.pop_Analysis.launch()
|
| 1238 |
if GlobalSettings.pop_Analysis.first_show == True:
|
| 1239 |
-
GlobalSettings.pop_Analysis
|
| 1240 |
GlobalSettings.pop_Analysis.first_show = False
|
| 1241 |
GlobalSettings.pop_Analysis.show()
|
| 1242 |
GlobalSettings.mainWindow.hide()
|
| 1243 |
except Exception as e:
|
| 1244 |
-
|
| 1245 |
-
logger.critical(e)
|
| 1246 |
-
logger.critical(traceback.format_exc())
|
| 1247 |
-
msgBox = QtWidgets.QMessageBox()
|
| 1248 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 1249 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 1250 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 1251 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 1252 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 1253 |
-
msgBox.exec()
|
| 1254 |
-
|
| 1255 |
-
exit(-1)
|
| 1256 |
|
| 1257 |
def annotation_information(self):
|
| 1258 |
try:
|
|
@@ -1268,46 +954,8 @@ class CMainWindow(QtWidgets.QMainWindow):
|
|
| 1268 |
msgBox.exec()
|
| 1269 |
|
| 1270 |
except Exception as e:
|
| 1271 |
-
|
| 1272 |
-
|
| 1273 |
-
logger.critical(traceback.format_exc())
|
| 1274 |
-
msgBox = QtWidgets.QMessageBox()
|
| 1275 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 1276 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 1277 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 1278 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 1279 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 1280 |
-
msgBox.exec()
|
| 1281 |
-
|
| 1282 |
-
exit(-1)
|
| 1283 |
-
|
| 1284 |
-
def open_ncbi_blast_web_page(self):
|
| 1285 |
-
try:
|
| 1286 |
-
webbrowser.open('https://blast.ncbi.nlm.nih.gov/Blast.cgi', new=2)
|
| 1287 |
-
except Exception as e:
|
| 1288 |
-
show_error("open_ncbi_blast_web_page() in main", e)
|
| 1289 |
-
|
| 1290 |
-
def open_ncbi_web_page(self):
|
| 1291 |
-
try:
|
| 1292 |
-
webbrowser.open('https://www.ncbi.nlm.nih.gov/', new=2)
|
| 1293 |
-
except Exception as e:
|
| 1294 |
-
show_error("open_ncbi_web_page() in main", e)
|
| 1295 |
-
|
| 1296 |
-
# def open_casper2_web_page(self):
|
| 1297 |
-
# try:
|
| 1298 |
-
# webbrowser.open('http://casper2.org/', new=2)
|
| 1299 |
-
# except Exception as e:
|
| 1300 |
-
# logger.critical("Error in open_casper2_web_page() in main.")
|
| 1301 |
-
# logger.critical(e)
|
| 1302 |
-
# logger.critical(traceback.format_exc())
|
| 1303 |
-
# exit(-1)
|
| 1304 |
-
|
| 1305 |
-
def visit_repo_func(self):
|
| 1306 |
-
try:
|
| 1307 |
-
webbrowser.open('https://github.com/TrinhLab/CASPERapp')
|
| 1308 |
-
except Exception as e:
|
| 1309 |
-
show_error("visit_repo_func() in main", e)
|
| 1310 |
-
|
| 1311 |
@QtCore.pyqtSlot()
|
| 1312 |
def view_results(self):
|
| 1313 |
try:
|
|
@@ -1319,18 +967,9 @@ class CMainWindow(QtWidgets.QMainWindow):
|
|
| 1319 |
self.Results.show()
|
| 1320 |
self.hide()
|
| 1321 |
except Exception as e:
|
| 1322 |
-
|
| 1323 |
-
logger.critical(e)
|
| 1324 |
-
logger.critical(traceback.format_exc())
|
| 1325 |
-
msgBox = QtWidgets.QMessageBox()
|
| 1326 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 1327 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 1328 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 1329 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 1330 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 1331 |
-
msgBox.exec()
|
| 1332 |
|
| 1333 |
-
|
| 1334 |
|
| 1335 |
def closeFunction(self):
|
| 1336 |
try:
|
|
@@ -1340,12 +979,11 @@ class CMainWindow(QtWidgets.QMainWindow):
|
|
| 1340 |
except AttributeError:
|
| 1341 |
print("No NCBI window to close.")
|
| 1342 |
|
| 1343 |
-
# Proceed with closing operations
|
| 1344 |
self.myClosingWindow.get_files()
|
| 1345 |
-
self.myClosingWindow
|
| 1346 |
self.myClosingWindow.show()
|
| 1347 |
except Exception as e:
|
| 1348 |
-
show_error("closeFunction() in main", e)
|
| 1349 |
|
| 1350 |
def close_app(self):
|
| 1351 |
try:
|
|
@@ -1359,360 +997,4 @@ class CMainWindow(QtWidgets.QMainWindow):
|
|
| 1359 |
self.closeFunction()
|
| 1360 |
self.close()
|
| 1361 |
except Exception as e:
|
| 1362 |
-
show_error("close_app() in main", e)
|
| 1363 |
-
|
| 1364 |
-
#startup window class
|
| 1365 |
-
class StartupWindow(QtWidgets.QMainWindow):
|
| 1366 |
-
def __init__(self):
|
| 1367 |
-
try:
|
| 1368 |
-
super(StartupWindow, self).__init__()
|
| 1369 |
-
|
| 1370 |
-
#load UX files
|
| 1371 |
-
try:
|
| 1372 |
-
uic.loadUi(GlobalSettings.appdir + 'startupCASPER.ui', self)
|
| 1373 |
-
self.setWindowIcon(QtGui.QIcon(GlobalSettings.appdir + "cas9image.png"))
|
| 1374 |
-
except Exception as e:
|
| 1375 |
-
logger.critical("Unable to load UX files for Startup Window.")
|
| 1376 |
-
logger.critical(e)
|
| 1377 |
-
logger.critical(traceback.format_exc())
|
| 1378 |
-
exit(-1)
|
| 1379 |
-
|
| 1380 |
-
#set "Main" button to be the default highlighted button on startup
|
| 1381 |
-
self.goToMain.setDefault(True)
|
| 1382 |
-
|
| 1383 |
-
#get current directory, and update based on current operating system
|
| 1384 |
-
self.currentDirectory = os.getcwd()
|
| 1385 |
-
self.databaseDirectory = self.loadDatabaseDirectory()
|
| 1386 |
-
GlobalSettings.CSPR_DB = self.databaseDirectory
|
| 1387 |
-
if platform.system() == "Windows":
|
| 1388 |
-
GlobalSettings.CSPR_DB = GlobalSettings.CSPR_DB.replace("/","\\")
|
| 1389 |
-
else:
|
| 1390 |
-
GlobalSettings.CSPR_DB = GlobalSettings.CSPR_DB.replace("\\","/")
|
| 1391 |
-
|
| 1392 |
-
#setup event handlers for startup buttons
|
| 1393 |
-
self.currentDirText.setText(self.databaseDirectory)
|
| 1394 |
-
self.changeDir.clicked.connect(self.change_directory)
|
| 1395 |
-
self.goToMain.clicked.connect(self.launchMainWindow)
|
| 1396 |
-
self.goToNewGenome.clicked.connect(self.launchNewGenome)
|
| 1397 |
-
|
| 1398 |
-
self.setWindowTitle("CASPER")
|
| 1399 |
-
self.setWindowIcon(Qt.QIcon(GlobalSettings.appdir + "cas9image.ico"))
|
| 1400 |
-
|
| 1401 |
-
#scale UI
|
| 1402 |
-
scale_ui(self)
|
| 1403 |
-
|
| 1404 |
-
except Exception as e:
|
| 1405 |
-
logger.critical("Error initializing StartupWindow class.")
|
| 1406 |
-
logger.critical(e)
|
| 1407 |
-
logger.critical(traceback.format_exc())
|
| 1408 |
-
exit(-1)
|
| 1409 |
-
|
| 1410 |
-
#event handler for user clicking the "Change..." button - used for changing CASPER database directory
|
| 1411 |
-
def change_directory(self):
|
| 1412 |
-
try:
|
| 1413 |
-
# Launch OS file browser
|
| 1414 |
-
newDirectory = QtWidgets.QFileDialog.getExistingDirectory(
|
| 1415 |
-
self, "Open a folder...", self.databaseDirectory, QtWidgets.QFileDialog.ShowDirsOnly)
|
| 1416 |
-
|
| 1417 |
-
# Check if selected path is a directory in the system
|
| 1418 |
-
if not os.path.isdir(newDirectory):
|
| 1419 |
-
show_message(
|
| 1420 |
-
fontSize=self.fontSize,
|
| 1421 |
-
icon=QtWidgets.QMessageBox.Icon.Critical,
|
| 1422 |
-
title="Not a directory",
|
| 1423 |
-
message="The directory you selected does not exist.",
|
| 1424 |
-
)
|
| 1425 |
-
return
|
| 1426 |
-
|
| 1427 |
-
# Ensure directory contains correct filepath format based on OS
|
| 1428 |
-
newDirectory = newDirectory.replace("/", "\\") if platform.system() == "Windows" else newDirectory.replace("\\", "/")
|
| 1429 |
-
|
| 1430 |
-
# Update text edit showing the current selected database directory
|
| 1431 |
-
self.currentDirText.setText(newDirectory)
|
| 1432 |
-
|
| 1433 |
-
# Update CASPER database directories
|
| 1434 |
-
self.databaseDirectory = newDirectory
|
| 1435 |
-
GlobalSettings.CSPR_DB = newDirectory
|
| 1436 |
-
|
| 1437 |
-
except Exception as e:
|
| 1438 |
-
show_error("change_directory() in startup window", e)
|
| 1439 |
-
|
| 1440 |
-
#function for loading the default database directory specified in CASPERinfo
|
| 1441 |
-
#returns: default database parsed from CASPERinfo
|
| 1442 |
-
def loadDatabaseDirectory(self):
|
| 1443 |
-
casperInfoPath = os.path.join(GlobalSettings.appdir, "CASPERinfo")
|
| 1444 |
-
defaultDirectory = "Where would you like to store CASPER database files?" # Default message if directory not found
|
| 1445 |
-
|
| 1446 |
-
try:
|
| 1447 |
-
with open(casperInfoPath, 'r') as file:
|
| 1448 |
-
for line in file:
|
| 1449 |
-
if 'DIRECTORY:' in line:
|
| 1450 |
-
defaultDirectory = line.strip().replace("DIRECTORY:", "").strip()
|
| 1451 |
-
break
|
| 1452 |
-
|
| 1453 |
-
# Ensure the directory path is formatted correctly based on the operating system
|
| 1454 |
-
if platform.system() == "Windows":
|
| 1455 |
-
defaultDirectory = defaultDirectory.replace("/", "\\")
|
| 1456 |
-
else:
|
| 1457 |
-
defaultDirectory = defaultDirectory.replace("\\", "/")
|
| 1458 |
-
|
| 1459 |
-
logger.debug("Successfully parsed CASPERinfo for default database directory.")
|
| 1460 |
-
return defaultDirectory
|
| 1461 |
-
|
| 1462 |
-
except Exception as e:
|
| 1463 |
-
logger.error(f"Error reading {casperInfoPath}: {e}")
|
| 1464 |
-
logger.error(traceback.format_exc())
|
| 1465 |
-
|
| 1466 |
-
return defaultDirectory
|
| 1467 |
-
|
| 1468 |
-
#function for saving the currently selected database directory to CASPERinfo to be the new default value on startup
|
| 1469 |
-
def saveDatabaseDirectory(self):
|
| 1470 |
-
try:
|
| 1471 |
-
#variable to hold the CASPERinfo data with new default directory change
|
| 1472 |
-
CASPERInfoNewData = ""
|
| 1473 |
-
|
| 1474 |
-
#new default directory string for CASPERinfo
|
| 1475 |
-
newDefaultDirectory = "DIRECTORY:" + str(self.databaseDirectory)
|
| 1476 |
-
|
| 1477 |
-
#open CASPERinfo file to read in the files data and add in new change
|
| 1478 |
-
try:
|
| 1479 |
-
CASPERInfo = open(GlobalSettings.appdir + "CASPERinfo", 'r+')
|
| 1480 |
-
CASPERinfoData = CASPERInfo.read()
|
| 1481 |
-
CASPERinfoData = CASPERinfoData.split('\n')
|
| 1482 |
-
for line in CASPERinfoData:
|
| 1483 |
-
#if directory line found, use new default directory string instead
|
| 1484 |
-
if 'DIRECTORY:' in line:
|
| 1485 |
-
CASPERInfoNewData = CASPERInfoNewData + "\n" + newDefaultDirectory
|
| 1486 |
-
else:
|
| 1487 |
-
CASPERInfoNewData = CASPERInfoNewData + "\n" + line
|
| 1488 |
-
CASPERInfoNewData = CASPERInfoNewData[1:]
|
| 1489 |
-
|
| 1490 |
-
#close CASPERinfo
|
| 1491 |
-
CASPERInfo.close()
|
| 1492 |
-
|
| 1493 |
-
#re-open the file and re-write it with current changes
|
| 1494 |
-
CASPERInfo = open(GlobalSettings.appdir + "CASPERinfo", 'w+')
|
| 1495 |
-
CASPERInfo.write(CASPERInfoNewData)
|
| 1496 |
-
CASPERInfo.close()
|
| 1497 |
-
logger.debug("Successfully updated CASPERinfo with new default database directory.")
|
| 1498 |
-
except Exception as e:
|
| 1499 |
-
logger.critical("Unable to write to CASPERinfo file to update database directory.")
|
| 1500 |
-
logger.critical(e)
|
| 1501 |
-
logger.critical(traceback.format_exc())
|
| 1502 |
-
msgBox = QtWidgets.QMessageBox()
|
| 1503 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 1504 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 1505 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 1506 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 1507 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 1508 |
-
msgBox.exec()
|
| 1509 |
-
|
| 1510 |
-
exit(-1)
|
| 1511 |
-
except Exception as e:
|
| 1512 |
-
logger.critical("Error in saveDatabaseDirectory() in startup window.")
|
| 1513 |
-
logger.critical(e)
|
| 1514 |
-
logger.critical(traceback.format_exc())
|
| 1515 |
-
msgBox = QtWidgets.QMessageBox()
|
| 1516 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 1517 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 1518 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 1519 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 1520 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 1521 |
-
msgBox.exec()
|
| 1522 |
-
|
| 1523 |
-
exit(-1)
|
| 1524 |
-
|
| 1525 |
-
# Event handler for user clicking the "New Genome" button - used for launching New Genome
|
| 1526 |
-
def launchNewGenome(self):
|
| 1527 |
-
try:
|
| 1528 |
-
# Make sure database directory variable is up-to-date based on what the user has in the text edit
|
| 1529 |
-
self.databaseDirectory = str(self.currentDirText.text())
|
| 1530 |
-
|
| 1531 |
-
if not os.path.isdir(self.databaseDirectory):
|
| 1532 |
-
show_message(
|
| 1533 |
-
fontSize=12,
|
| 1534 |
-
icon=QtWidgets.QMessageBox.Icon.Critical,
|
| 1535 |
-
title="Not a directory",
|
| 1536 |
-
message="The directory you selected does not exist.",
|
| 1537 |
-
)
|
| 1538 |
-
return
|
| 1539 |
-
|
| 1540 |
-
# Change directories to the specified database directory provided
|
| 1541 |
-
os.chdir(self.databaseDirectory)
|
| 1542 |
-
|
| 1543 |
-
# Write out the database directory to CASPERinfo to be the new default loaded value
|
| 1544 |
-
self.saveDatabaseDirectory()
|
| 1545 |
-
|
| 1546 |
-
# Update global database variable
|
| 1547 |
-
GlobalSettings.CSPR_DB = self.databaseDirectory
|
| 1548 |
-
|
| 1549 |
-
# Create app directories
|
| 1550 |
-
initialize_app_directories()
|
| 1551 |
-
|
| 1552 |
-
# Launch New Genome window
|
| 1553 |
-
self.launch_new_genome()
|
| 1554 |
-
|
| 1555 |
-
self.close()
|
| 1556 |
-
except Exception as e:
|
| 1557 |
-
show_error("launchNewGenome() in startup window", e)
|
| 1558 |
-
|
| 1559 |
-
def launch_new_genome(self):
|
| 1560 |
-
try:
|
| 1561 |
-
GlobalSettings.mainWindow.launch_newGenome()
|
| 1562 |
-
logger.debug("Successfully initialized New Genome in startup window.")
|
| 1563 |
-
except Exception as e:
|
| 1564 |
-
show_error("launch_new_genome() in startup window", e)
|
| 1565 |
-
|
| 1566 |
-
# Event handler for user clicking "Main Program" button - used to launch Main Window
|
| 1567 |
-
def launchMainWindow(self):
|
| 1568 |
-
try:
|
| 1569 |
-
# Make sure database directory variable is up-to-date based on what the user has in the text edit
|
| 1570 |
-
self.databaseDirectory = str(self.currentDirText.text())
|
| 1571 |
-
|
| 1572 |
-
# Make sure the path is a valid path before launching New Genome
|
| 1573 |
-
if not os.path.isdir(self.databaseDirectory):
|
| 1574 |
-
show_message(
|
| 1575 |
-
fontSize=12,
|
| 1576 |
-
icon=QtWidgets.QMessageBox.Icon.Critical,
|
| 1577 |
-
title="Not a directory",
|
| 1578 |
-
message="The directory you selected does not exist.",
|
| 1579 |
-
)
|
| 1580 |
-
return
|
| 1581 |
-
|
| 1582 |
-
# Check if database directory has CSPR files in it
|
| 1583 |
-
if not any(file.endswith(".cspr") for file in os.listdir(self.databaseDirectory)):
|
| 1584 |
-
show_message(
|
| 1585 |
-
fontSize=12,
|
| 1586 |
-
icon=QtWidgets.QMessageBox.Icon.Critical,
|
| 1587 |
-
title="Directory is invalid!",
|
| 1588 |
-
message="You must select a directory with CSPR Files!",
|
| 1589 |
-
)
|
| 1590 |
-
return
|
| 1591 |
-
|
| 1592 |
-
# Change directory to database directory
|
| 1593 |
-
os.chdir(self.databaseDirectory)
|
| 1594 |
-
|
| 1595 |
-
# Update database directory global variable
|
| 1596 |
-
GlobalSettings.CSPR_DB = self.databaseDirectory
|
| 1597 |
-
|
| 1598 |
-
# Save database directory to CASPERinfo
|
| 1599 |
-
self.saveDatabaseDirectory()
|
| 1600 |
-
|
| 1601 |
-
initialize_app_directories()
|
| 1602 |
-
|
| 1603 |
-
# Fill in organism/endo/annotation dropdown information for main, mulit-targeting, and populatin analysis
|
| 1604 |
-
self.load_dropdown_data()
|
| 1605 |
-
|
| 1606 |
-
# Show main window
|
| 1607 |
-
if GlobalSettings.mainWindow.first_show:
|
| 1608 |
-
GlobalSettings.mainWindow.first_show = False
|
| 1609 |
-
GlobalSettings.mainWindow.show()
|
| 1610 |
-
self.close()
|
| 1611 |
-
|
| 1612 |
-
except Exception as e:
|
| 1613 |
-
show_error("launchMainWindow() in startup window", e)
|
| 1614 |
-
|
| 1615 |
-
def load_dropdown_data(self):
|
| 1616 |
-
try:
|
| 1617 |
-
GlobalSettings.mainWindow.getData()
|
| 1618 |
-
GlobalSettings.mainWindow.fill_annotation_dropdown()
|
| 1619 |
-
logger.debug("Successfully loaded organism/endo/annotation drop down information in Main.")
|
| 1620 |
-
except Exception as e:
|
| 1621 |
-
show_error("load_dropdown_data() in Main", e)
|
| 1622 |
-
|
| 1623 |
-
try:
|
| 1624 |
-
GlobalSettings.MTWin.launch()
|
| 1625 |
-
logger.debug("Successfully loaded organism/endo drop down information in Multi-targeting.")
|
| 1626 |
-
except Exception as e:
|
| 1627 |
-
show_error("load_dropdown_data() in Multi-targeting", e)
|
| 1628 |
-
|
| 1629 |
-
try:
|
| 1630 |
-
GlobalSettings.pop_Analysis.launch()
|
| 1631 |
-
logger.debug("Successfully loaded organism/endo drop down information in Population Analysis.")
|
| 1632 |
-
except Exception as e:
|
| 1633 |
-
show_error("load_dropdown_data() in Population Analysis", e)
|
| 1634 |
-
|
| 1635 |
-
def initialize_app_directories():
|
| 1636 |
-
required_dirs = ["FNA", "GBFF"]
|
| 1637 |
-
for directory in required_dirs:
|
| 1638 |
-
path = os.path.join(GlobalSettings.CSPR_DB, directory)
|
| 1639 |
-
if not os.path.exists(path):
|
| 1640 |
-
os.makedirs(path, exist_ok=True)
|
| 1641 |
-
logging.info(f"Directory created: {path}")
|
| 1642 |
-
|
| 1643 |
-
def setup_logger():
|
| 1644 |
-
logger.info(f"System OS: {platform.system()}")
|
| 1645 |
-
|
| 1646 |
-
if hasattr(sys, 'frozen'):
|
| 1647 |
-
#log CASPER is in packaged format
|
| 1648 |
-
logger.info("Running a packaged version of CASPER.")
|
| 1649 |
-
GlobalSettings.appdir = sys.executable
|
| 1650 |
-
if platform.system() == 'Windows':
|
| 1651 |
-
GlobalSettings.appdir = sys._MEIPASS + "\\"
|
| 1652 |
-
else:
|
| 1653 |
-
GlobalSettings.appdir = GlobalSettings.appdir[:GlobalSettings.appdir.rfind("Contents/") + 9] + "Resources/"
|
| 1654 |
-
|
| 1655 |
-
else:
|
| 1656 |
-
# log CASPER is not in packaged format
|
| 1657 |
-
logger.info("Running a non-packaged version of CASPER.")
|
| 1658 |
-
GlobalSettings.appdir = os.path.dirname(os.path.abspath(__file__)) + ('\\' if platform.system() == 'Windows' else '/')
|
| 1659 |
-
|
| 1660 |
-
fh = logging.FileHandler(GlobalSettings.appdir + 'logs/CASPER.log', mode='w')
|
| 1661 |
-
fh_formatter = logging.Formatter('%(asctime)s %(levelname)s %(lineno)d:%(filename)s(%(process)d) - %(message)s')
|
| 1662 |
-
fh.setFormatter(fh_formatter)
|
| 1663 |
-
fh.setLevel(logging.DEBUG)
|
| 1664 |
-
GlobalSettings.logger.addHandler(fh)
|
| 1665 |
-
|
| 1666 |
-
# def update_directory(current_directory, fontSize, update_ui_callback):
|
| 1667 |
-
# try:
|
| 1668 |
-
# filed = QtWidgets.QFileDialog()
|
| 1669 |
-
# new_directory = QtWidgets.QFileDialog.getExistingDirectory(
|
| 1670 |
-
# filed, "Open a folder...", current_directory, QtWidgets.QFileDialog.ShowDirsOnly)
|
| 1671 |
-
|
| 1672 |
-
# if not os.path.isdir(new_directory):
|
| 1673 |
-
# show_message("Not a directory", "The directory you selected does not exist.", fontSize)
|
| 1674 |
-
# return
|
| 1675 |
-
|
| 1676 |
-
# if not any(file.endswith(".cspr") for file in os.listdir(new_directory)):
|
| 1677 |
-
# show_message("Directory is invalid!", "You must select a directory with CSPR Files!", fontSize)
|
| 1678 |
-
# return
|
| 1679 |
-
|
| 1680 |
-
# if platform.system() == "Windows":
|
| 1681 |
-
# new_directory = new_directory.replace("/", "\\")
|
| 1682 |
-
|
| 1683 |
-
# os.chdir(new_directory)
|
| 1684 |
-
# GlobalSettings.CSPR_DB = new_directory
|
| 1685 |
-
# update_ui_callback(new_directory)
|
| 1686 |
-
|
| 1687 |
-
# except Exception as e:
|
| 1688 |
-
# show_critical_error("Error in updating directory", e, fontSize)
|
| 1689 |
-
|
| 1690 |
-
def main():
|
| 1691 |
-
setup_logger()
|
| 1692 |
-
app = QtWidgets.QApplication(sys.argv)
|
| 1693 |
-
app.setOrganizationName("TrinhLab-UTK")
|
| 1694 |
-
app.setApplicationName("CASPER")
|
| 1695 |
-
|
| 1696 |
-
#load startup window
|
| 1697 |
-
try:
|
| 1698 |
-
# Initialize windows
|
| 1699 |
-
startup = StartupWindow()
|
| 1700 |
-
logger.debug("Successfully initialized Startup Window.")
|
| 1701 |
-
|
| 1702 |
-
GlobalSettings.mainWindow = CMainWindow(os.getcwd())
|
| 1703 |
-
logger.debug("Successfully initialized Main Window.")
|
| 1704 |
-
|
| 1705 |
-
GlobalSettings.MTWin = multitargeting.Multitargeting()
|
| 1706 |
-
logger.debug("Successfully initialized Multi-targeting Window.")
|
| 1707 |
-
|
| 1708 |
-
GlobalSettings.pop_Analysis = populationAnalysis.Pop_Analysis()
|
| 1709 |
-
logger.debug("Successfully initialized Population Analysis Window.")
|
| 1710 |
-
|
| 1711 |
-
center_ui(startup)
|
| 1712 |
-
startup.show()
|
| 1713 |
-
sys.exit(app.exec_())
|
| 1714 |
-
except Exception as e:
|
| 1715 |
-
show_error("An error occurred during application initialization", e)
|
| 1716 |
-
|
| 1717 |
-
if __name__ == '__main__':
|
| 1718 |
-
main()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
import platform
|
| 2 |
+
import controllers.ncbi as ncbi
|
| 3 |
+
import os
|
| 4 |
+
from utils.Algorithms import get_table_headers
|
| 5 |
+
from models.CSPRparser import CSPRparser
|
| 6 |
import glob
|
| 7 |
import traceback
|
| 8 |
+
import models.GlobalSettings as GlobalSettings
|
| 9 |
+
from PyQt5 import QtWidgets, QtGui, QtCore, uic, Qt
|
| 10 |
+
from utils.ui import scale_ui, center_ui, show_message, show_error
|
| 11 |
+
from views.annotation_functions import *
|
| 12 |
+
from views.AnnotationParser import Annotation_Parser
|
| 13 |
+
from views.AnnotationWindow import AnnotationWindow
|
| 14 |
+
import views.genomeBrowser as genomeBrowser
|
| 15 |
+
from views.NewGenome import NewGenome
|
| 16 |
+
from views.NewEndonuclease import NewEndonuclease
|
| 17 |
+
from controllers.CoTargeting import CoTargeting
|
| 18 |
+
from views.generateLib import genLibrary
|
| 19 |
+
import webbrowser
|
| 20 |
+
from controllers.Results import Results
|
| 21 |
+
from views.export_tool import export_tool
|
| 22 |
+
from views.closingWin import closingWindow
|
| 23 |
+
from utils.web import ncbi_page, repo_page, ncbi_blast_page
|
| 24 |
+
|
| 25 |
logger = GlobalSettings.logger
|
| 26 |
|
| 27 |
fontSize = 12
|
| 28 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 29 |
class CMainWindow(QtWidgets.QMainWindow):
|
|
|
|
| 30 |
def __init__(self, info_path):
|
| 31 |
super(CMainWindow, self).__init__()
|
| 32 |
+
uic.loadUi(GlobalSettings.appdir + 'ui/CASPER_main.ui', self)
|
| 33 |
self.dbpath = ""
|
| 34 |
self.inputstring = "" # This is the search string
|
| 35 |
self.info_path = info_path
|
|
|
|
| 85 |
""" Connect functions to actions (menu bar) """
|
| 86 |
self.actionOpen_Genome_Browser.triggered.connect(self.launch_newGenomeBrowser)
|
| 87 |
self.actionExit.triggered.connect(self.close_app)
|
| 88 |
+
self.visit_repo.triggered.connect(repo_page)
|
| 89 |
self.actionChange_Directory.triggered.connect(self.change_directory)
|
| 90 |
+
self.actionNCBI.triggered.connect(ncbi_page)
|
| 91 |
# self.actionCasper2.triggered.connect(self.open_casper2_web_page)
|
| 92 |
+
self.actionNCBI_BLAST.triggered.connect(ncbi_blast_page)
|
| 93 |
|
| 94 |
|
| 95 |
|
| 96 |
self.progressBar.setMinimum(0)
|
| 97 |
self.progressBar.setMaximum(100)
|
| 98 |
self.progressBar.reset()
|
| 99 |
+
self.Annotation_Window = AnnotationWindow(info_path)
|
| 100 |
self.geneEntryField.setPlaceholderText("Example Inputs: \n\n"
|
| 101 |
"Option 1: Feature (ID, Locus Tag, or Name)\n"
|
| 102 |
"Example: 854068/YOL086C/ADH1 for S. cerevisiae alcohol dehydrogenase 1\n\n"
|
|
|
|
| 121 |
self.genomebrowser = genomeBrowser.genomebrowser()
|
| 122 |
self.launch_ncbi_button.clicked.connect(self.launch_ncbi)
|
| 123 |
|
|
|
|
| 124 |
self.first_show = True
|
| 125 |
+
scale_ui(self, custom_scale_width=1150, custom_scale_height=650)
|
| 126 |
|
| 127 |
# this function prepares everything for the generate library function
|
| 128 |
# it is very similar to the gather settings, how ever it stores the data instead of calling the Annotation Window class
|
|
|
|
| 205 |
else:
|
| 206 |
self.progressBar.setValue(0)
|
| 207 |
except Exception as e:
|
| 208 |
+
show_error("Error in prep_genlib() in main", e)
|
| 209 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 210 |
# Function for collecting the settings from the input field and transferring them to run_results
|
| 211 |
def gather_settings(self):
|
| 212 |
try:
|
|
|
|
| 256 |
sinput = self.inputstring
|
| 257 |
self.run_results("sequence", sinput, same_search)
|
| 258 |
except Exception as e:
|
| 259 |
+
show_error("Error in gather_settings() in main", e)
|
| 260 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 261 |
# ---- Following functions are for running the auxillary algorithms and windows ---- #
|
| 262 |
# this function is parses the annotation file given, and then goes through and goes onto results
|
| 263 |
# it will call other versions of collect_table_data and fill_table that work with these file types
|
|
|
|
| 579 |
|
| 580 |
|
| 581 |
except Exception as e:
|
| 582 |
+
show_error("Error in run_results() in main", e)
|
| 583 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 584 |
def handle_feature_search(self, input_string, open_anno_window):
|
| 585 |
file_type = self.annotation_parser.find_which_file_version()
|
| 586 |
if file_type == -1 or self.annotation_files.currentText() == "None":
|
|
|
|
| 600 |
self.hide()
|
| 601 |
self.newGenome.show()
|
| 602 |
except Exception as e:
|
| 603 |
+
show_error("Error in launch_newGenome() in main", e)
|
| 604 |
|
|
|
|
| 605 |
def launch_newEndonuclease(self):
|
| 606 |
try:
|
| 607 |
+
center_ui(self.newEndonuclease)
|
|
|
|
| 608 |
self.newEndonuclease.show()
|
| 609 |
self.newEndonuclease.activateWindow()
|
| 610 |
except Exception as e:
|
| 611 |
+
show_error("Error in launch_newEndonuclease() in main", e)
|
| 612 |
|
| 613 |
#launch genome browser tool
|
| 614 |
def launch_newGenomeBrowser(self):
|
| 615 |
try:
|
| 616 |
self.genomebrowser.createGraph(self)
|
| 617 |
except Exception as e:
|
| 618 |
+
show_error("Error in launch_newGenomeBrowser() in main", e)
|
| 619 |
|
|
|
|
| 620 |
def launch_ncbi(self):
|
| 621 |
try:
|
| 622 |
msgBox = QtWidgets.QMessageBox()
|
|
|
|
| 630 |
|
| 631 |
if self.ncbi.first_show:
|
| 632 |
self.ncbi.first_show = False
|
| 633 |
+
center_ui(self.ncbi)
|
| 634 |
|
| 635 |
self.ncbi.show()
|
| 636 |
self.ncbi.activateWindow()
|
|
|
|
| 678 |
self.pushButton_ViewTargets.setEnabled(True)
|
| 679 |
self.GenerateLibrary.setEnabled(True)
|
| 680 |
except Exception as e:
|
| 681 |
+
show_error("Error in collect_table_data_nonkegg() in main", e)
|
| 682 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 683 |
def separate_line(self, input_string):
|
| 684 |
try:
|
| 685 |
export_array = []
|
|
|
|
| 694 |
export_array.append(input_string[:index])
|
| 695 |
input_string = input_string[index + 1:]
|
| 696 |
except Exception as e:
|
| 697 |
+
show_error("Error in seperate_line() in main", e)
|
| 698 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 699 |
def removeWhiteSpace(self, strng):
|
| 700 |
try:
|
| 701 |
while True:
|
|
|
|
| 707 |
return strng
|
| 708 |
strng = strng[:len(strng) - 1]
|
| 709 |
except Exception as e:
|
| 710 |
+
show_error("Error in removeWhiteSpace() in main", e)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 711 |
|
| 712 |
# Function to enable and disable the Annotation function if searching by position or sequence
|
| 713 |
def toggle_annotation(self):
|
|
|
|
| 717 |
else:
|
| 718 |
self.Step2.setEnabled(True)
|
| 719 |
except Exception as e:
|
| 720 |
+
show_error("Error in toggle_annotation() in main", e)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 721 |
|
| 722 |
def fill_annotation_dropdown(self):
|
| 723 |
try:
|
|
|
|
| 737 |
self.annotation_files.addItems(annotation_files)
|
| 738 |
self.annotation_files.addItems(["None"])
|
| 739 |
except Exception as e:
|
| 740 |
+
show_error("Error in fill_annotation_dropdown() in main", e)
|
| 741 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 742 |
def make_dictonary(self):
|
| 743 |
try:
|
| 744 |
url = "https://www.genome.jp/dbget-bin/get_linkdb?-t+genes+gn:" + self.TNumbers[
|
|
|
|
| 773 |
self.gene_list[key] = [seq]
|
| 774 |
z = 5
|
| 775 |
except Exception as e:
|
| 776 |
+
show_error("Error in make_dictionary() in main", e)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 777 |
|
| 778 |
def organism_finder(self, long_str):
|
| 779 |
try:
|
|
|
|
| 785 |
index = index + 1
|
| 786 |
return long_str[:semi - index]
|
| 787 |
except Exception as e:
|
| 788 |
+
show_error("Error in organism_finder() in main", e)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 789 |
|
| 790 |
# This method is for testing the execution of a button call to make sure the button is linked properly
|
| 791 |
def testexe(self):
|
|
|
|
| 806 |
else:
|
| 807 |
pass
|
| 808 |
except Exception as e:
|
| 809 |
+
show_error("Error in testexe() in main", e)
|
| 810 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 811 |
def getData(self):
|
| 812 |
try:
|
| 813 |
try:
|
|
|
|
| 860 |
self.endoChoice.addItems(self.organisms_to_endos[str(self.orgChoice.currentText())])
|
| 861 |
self.orgChoice.currentIndexChanged.connect(self.changeEndos)
|
| 862 |
except Exception as e:
|
| 863 |
+
show_error("Error in getData() in main.", e)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 864 |
|
| 865 |
def changeEndos(self):
|
| 866 |
try:
|
|
|
|
| 878 |
self.radioButton_Gene.hide()
|
| 879 |
self.radioButton_Position.hide()
|
| 880 |
except Exception as e:
|
| 881 |
+
show_error("Error in changeEndos() in main", e)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 882 |
|
| 883 |
def change_directory(self):
|
| 884 |
try:
|
|
|
|
| 915 |
except Exception as e:
|
| 916 |
show_error("Error in change_directory() in main.", e)
|
| 917 |
|
|
|
|
| 918 |
def changeto_multitargeting(self):
|
| 919 |
try:
|
| 920 |
os.chdir(os.getcwd())
|
|
|
|
| 926 |
GlobalSettings.mainWindow.hide()
|
| 927 |
|
| 928 |
except Exception as e:
|
| 929 |
+
show_error("Error in changeto_multitargeting() in main.", e)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 930 |
|
| 931 |
#change to population analysis window
|
| 932 |
def changeto_population_Analysis(self):
|
| 933 |
try:
|
| 934 |
GlobalSettings.pop_Analysis.launch()
|
| 935 |
if GlobalSettings.pop_Analysis.first_show == True:
|
| 936 |
+
center_ui(GlobalSettings.pop_Analysis)
|
| 937 |
GlobalSettings.pop_Analysis.first_show = False
|
| 938 |
GlobalSettings.pop_Analysis.show()
|
| 939 |
GlobalSettings.mainWindow.hide()
|
| 940 |
except Exception as e:
|
| 941 |
+
show_error("Error in changeto_population_Analysis() in main.", e)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 942 |
|
| 943 |
def annotation_information(self):
|
| 944 |
try:
|
|
|
|
| 954 |
msgBox.exec()
|
| 955 |
|
| 956 |
except Exception as e:
|
| 957 |
+
show_error("Error in annotation_information() in main.", e)
|
| 958 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 959 |
@QtCore.pyqtSlot()
|
| 960 |
def view_results(self):
|
| 961 |
try:
|
|
|
|
| 967 |
self.Results.show()
|
| 968 |
self.hide()
|
| 969 |
except Exception as e:
|
| 970 |
+
show_error("Error in view_results() in main", e)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 971 |
|
| 972 |
+
|
| 973 |
|
| 974 |
def closeFunction(self):
|
| 975 |
try:
|
|
|
|
| 979 |
except AttributeError:
|
| 980 |
print("No NCBI window to close.")
|
| 981 |
|
|
|
|
| 982 |
self.myClosingWindow.get_files()
|
| 983 |
+
center_ui(self.myClosingWindow)
|
| 984 |
self.myClosingWindow.show()
|
| 985 |
except Exception as e:
|
| 986 |
+
show_error("Error in closeFunction() in main", e)
|
| 987 |
|
| 988 |
def close_app(self):
|
| 989 |
try:
|
|
|
|
| 997 |
self.closeFunction()
|
| 998 |
self.close()
|
| 999 |
except Exception as e:
|
| 1000 |
+
show_error("Error in close_app() in main", e)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
File without changes
|
|
@@ -0,0 +1,228 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import sys, os
|
| 2 |
+
from PyQt5 import QtWidgets, uic, QtGui, QtCore, Qt
|
| 3 |
+
import models.GlobalSettings as GlobalSettings
|
| 4 |
+
from PyQt5.QtGui import QIntValidator
|
| 5 |
+
import traceback
|
| 6 |
+
import math
|
| 7 |
+
from utils.ui import show_message, show_error, scale_ui, center_ui
|
| 8 |
+
|
| 9 |
+
logger = GlobalSettings.logger
|
| 10 |
+
|
| 11 |
+
class NewEndonuclease(QtWidgets.QMainWindow):
|
| 12 |
+
def __init__(self):
|
| 13 |
+
print("Initializing NewEndonuclease class")
|
| 14 |
+
try:
|
| 15 |
+
super(NewEndonuclease, self).__init__()
|
| 16 |
+
uic.loadUi(GlobalSettings.appdir + 'ui/newendonuclease.ui', self)
|
| 17 |
+
self.setWindowIcon(Qt.QIcon(GlobalSettings.appdir + "cas9image.ico"))
|
| 18 |
+
self.setWindowTitle('New Endonuclease')
|
| 19 |
+
self.error = False
|
| 20 |
+
pamFlag = False
|
| 21 |
+
|
| 22 |
+
self.onList = []
|
| 23 |
+
self.offList = []
|
| 24 |
+
|
| 25 |
+
self.onList, self.offList = self.get_on_off_data() ### Call function to fill on- and off- data name lists
|
| 26 |
+
|
| 27 |
+
for name in self.onList: ### Add on-target names to drop-down
|
| 28 |
+
self.comboBox.addItem(str(name))
|
| 29 |
+
|
| 30 |
+
for name in self.offList: ### Add off-target names to drop-down
|
| 31 |
+
self.comboBox_2.addItem(str(name))
|
| 32 |
+
|
| 33 |
+
self.submit_button.clicked.connect(self.submit)
|
| 34 |
+
self.cancel_button.clicked.connect(self.cancel)
|
| 35 |
+
|
| 36 |
+
### Set up validators for input fields:
|
| 37 |
+
reg_ex1 = QtCore.QRegExp("[^/\\\\_]+") # No slashes or underscores
|
| 38 |
+
reg_ex2 = QtCore.QRegExp("[^/\\\\_\\s]+") # No slashes, underscores, or spaces
|
| 39 |
+
reg_ex3 = QtCore.QRegExp("[acdefghiklmnpqrstvwyACDEFGHIKLMNPQRSTVWY\S]+") # Only approved PAM characters and no spaces
|
| 40 |
+
input_validator1 = QtGui.QRegExpValidator(reg_ex1, self)
|
| 41 |
+
input_validator2 = QtGui.QRegExpValidator(reg_ex2, self)
|
| 42 |
+
input_validator3 = QtGui.QRegExpValidator(reg_ex3, self)
|
| 43 |
+
self.organism_name.setValidator(input_validator1)
|
| 44 |
+
self.abbreviation.setValidator(input_validator2)
|
| 45 |
+
self.pam_sequence.setValidator(input_validator3)
|
| 46 |
+
|
| 47 |
+
self.seed_length.setValidator(QIntValidator(0,30,self.seed_length))
|
| 48 |
+
self.five_length.setValidator(QIntValidator(0,20,self.five_length))
|
| 49 |
+
self.three_length.setValidator(QIntValidator(0,20,self.three_length))
|
| 50 |
+
|
| 51 |
+
groupbox_style = """
|
| 52 |
+
QGroupBox:title{subcontrol-origin: margin;
|
| 53 |
+
left: 10px;
|
| 54 |
+
padding: 0 5px 0 5px;}
|
| 55 |
+
QGroupBox#groupBox{border: 2px solid rgb(111,181,110);
|
| 56 |
+
border-radius: 9px;
|
| 57 |
+
font: bold 14pt 'Arial';
|
| 58 |
+
margin-top: 10px;}"""
|
| 59 |
+
|
| 60 |
+
self.groupBox.setStyleSheet(groupbox_style)
|
| 61 |
+
self.groupBox_2.setStyleSheet(groupbox_style.replace("groupBox","groupBox_2"))
|
| 62 |
+
self.groupBox_3.setStyleSheet(groupbox_style.replace("groupBox","groupBox_3"))
|
| 63 |
+
|
| 64 |
+
scale_ui(self, custom_scale_width=480, custom_scale_height=615)
|
| 65 |
+
except Exception as e:
|
| 66 |
+
show_error("Error initializing NewEndonuclease class.", e)
|
| 67 |
+
|
| 68 |
+
#helper function for writing new endo information to CASPERinfo - used by submit()
|
| 69 |
+
def writeNewEndonuclease(self, newEndonucleaseStr):
|
| 70 |
+
try:
|
| 71 |
+
with open(GlobalSettings.appdir + 'CASPERinfo', 'r') as f, open(GlobalSettings.appdir + "new_file", 'w+') as f1:
|
| 72 |
+
for line in f:
|
| 73 |
+
f1.write(line)
|
| 74 |
+
if 'ENDONUCLEASES' in line:
|
| 75 |
+
f1.write(newEndonucleaseStr + '\n') # Move f1.write(line) above, to write above instead
|
| 76 |
+
os.remove(GlobalSettings.appdir + "CASPERinfo")
|
| 77 |
+
os.rename(GlobalSettings.appdir + "new_file",
|
| 78 |
+
GlobalSettings.appdir + "CASPERinfo") # Rename the new file
|
| 79 |
+
except Exception as e:
|
| 80 |
+
show_error("Error in writeNewEndonuclease() in New Endonuclease.", e)
|
| 81 |
+
|
| 82 |
+
#submit new endo to CASPERinfo file
|
| 83 |
+
def submit(self):
|
| 84 |
+
try:
|
| 85 |
+
# This is executed when the button is pressed
|
| 86 |
+
name = str(self.organism_name.text())
|
| 87 |
+
abbr = str(self.abbreviation.text())
|
| 88 |
+
crisprtype = str(self.crispr_type.text())
|
| 89 |
+
seed_len = str(self.seed_length.text())
|
| 90 |
+
five_len = str(self.five_length.text())
|
| 91 |
+
three_len = str(self.three_length.text())
|
| 92 |
+
pam = str(self.pam_sequence.text()).upper()
|
| 93 |
+
### Check for multiple PAMs and format if present
|
| 94 |
+
if len(pam.split(','))>0:
|
| 95 |
+
pam = [x.strip() for x in pam.split(',')]
|
| 96 |
+
pam = ",".join(pam)
|
| 97 |
+
### Check for PAM directionality
|
| 98 |
+
if self.five_pam.isChecked():
|
| 99 |
+
pam_dir = str(5)
|
| 100 |
+
else:
|
| 101 |
+
pam_dir = str(3)
|
| 102 |
+
on_scoring = str(self.comboBox.currentText())
|
| 103 |
+
off_scoring = str(self.comboBox_2.currentText())
|
| 104 |
+
length = len(seed_len) + len(five_len) + len(three_len)
|
| 105 |
+
argument_list = [abbr, pam, five_len, seed_len, three_len, pam_dir, name, crisprtype, on_scoring, off_scoring]
|
| 106 |
+
validPAM = ('A', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'V', 'W', 'Y')
|
| 107 |
+
self.error = False;
|
| 108 |
+
|
| 109 |
+
### Error checking for PAM alphabet
|
| 110 |
+
for letter in pam:
|
| 111 |
+
if (letter not in validPAM):
|
| 112 |
+
show_message(
|
| 113 |
+
fontSize=12,
|
| 114 |
+
icon=QtWidgets.QMessageBox.Icon.Critical,
|
| 115 |
+
title="Invalid PAM",
|
| 116 |
+
message="Invalid characters in PAM Sequence."
|
| 117 |
+
)
|
| 118 |
+
return True
|
| 119 |
+
### Error checking for filling out all fields
|
| 120 |
+
for arg in argument_list:
|
| 121 |
+
if ';' in arg:
|
| 122 |
+
show_message(
|
| 123 |
+
fontSize=12,
|
| 124 |
+
icon=QtWidgets.QMessageBox.Icon.Critical,
|
| 125 |
+
title="Invalid Semicolon",
|
| 126 |
+
message="Invalid character used: ';'."
|
| 127 |
+
)
|
| 128 |
+
return True
|
| 129 |
+
elif arg == "":
|
| 130 |
+
show_message(
|
| 131 |
+
fontSize=12,
|
| 132 |
+
icon=QtWidgets.QMessageBox.Icon.Critical,
|
| 133 |
+
title="Empty Field",
|
| 134 |
+
message="Please fill in all fields."
|
| 135 |
+
)
|
| 136 |
+
return True
|
| 137 |
+
else:
|
| 138 |
+
pass
|
| 139 |
+
|
| 140 |
+
### Check for duplicate endo abbreviations
|
| 141 |
+
for key in GlobalSettings.mainWindow.organisms_to_endos:
|
| 142 |
+
endo = GlobalSettings.mainWindow.organisms_to_endos[key]
|
| 143 |
+
if abbr in endo:
|
| 144 |
+
show_message(
|
| 145 |
+
fontSize=12,
|
| 146 |
+
icon=QtWidgets.QMessageBox.Icon.Critical,
|
| 147 |
+
title="Duplicate endo name.",
|
| 148 |
+
message="The given abbreviation already exists. Please choose a unique identifier."
|
| 149 |
+
)
|
| 150 |
+
return True
|
| 151 |
+
else:
|
| 152 |
+
pass
|
| 153 |
+
|
| 154 |
+
myString = ""
|
| 155 |
+
for i, arg in enumerate(argument_list):
|
| 156 |
+
if i == len(argument_list)-1: ### Last argument in list
|
| 157 |
+
myString += str(arg)
|
| 158 |
+
else:
|
| 159 |
+
myString += str(arg) + ";"
|
| 160 |
+
|
| 161 |
+
self.writeNewEndonuclease(myString)
|
| 162 |
+
|
| 163 |
+
### Refresh endonuclease dropdown in New Genome
|
| 164 |
+
GlobalSettings.mainWindow.newGenome.fillEndo()
|
| 165 |
+
|
| 166 |
+
self.clear_all()
|
| 167 |
+
self.close()
|
| 168 |
+
except Exception as e:
|
| 169 |
+
show_error("Error in submit() in New Endonuclease.", e)
|
| 170 |
+
|
| 171 |
+
#cancel and close window
|
| 172 |
+
def cancel(self):
|
| 173 |
+
try:
|
| 174 |
+
self.clear_all()
|
| 175 |
+
self.close()
|
| 176 |
+
except Exception as e:
|
| 177 |
+
show_error("Error in cancel() in New Endonuclease.", e)
|
| 178 |
+
|
| 179 |
+
# This function clears all of the line edits
|
| 180 |
+
def clear_all(self):
|
| 181 |
+
try:
|
| 182 |
+
self.organism_name.clear()
|
| 183 |
+
self.abbreviation.clear()
|
| 184 |
+
self.crispr_type.clear()
|
| 185 |
+
self.seed_length.clear()
|
| 186 |
+
self.five_length.clear()
|
| 187 |
+
self.three_length.clear()
|
| 188 |
+
self.pam_sequence.clear()
|
| 189 |
+
except Exception as e:
|
| 190 |
+
show_error("Error in clear_all() in New Endonuclease.", e)
|
| 191 |
+
|
| 192 |
+
# This function parses CASPERinfo to return the names (in lists) of all on-target and off-target scoring data
|
| 193 |
+
def get_on_off_data(self):
|
| 194 |
+
try:
|
| 195 |
+
filename = GlobalSettings.appdir + "CASPERinfo"
|
| 196 |
+
retList_on = []
|
| 197 |
+
retList_off = []
|
| 198 |
+
with open(filename, 'r') as f:
|
| 199 |
+
lines = f.readlines()
|
| 200 |
+
for i, line in enumerate(lines):
|
| 201 |
+
line = str(line)
|
| 202 |
+
if "ON-TARGET DATA" in line:
|
| 203 |
+
index = i
|
| 204 |
+
while "-----" not in line:
|
| 205 |
+
if "DATA:" in line:
|
| 206 |
+
retList_on.append(line.split("DATA:")[-1].strip()) ### Append name of scoring data to on-target name list
|
| 207 |
+
line = lines[index+1]
|
| 208 |
+
index += 1
|
| 209 |
+
else:
|
| 210 |
+
line = lines[index+1]
|
| 211 |
+
index += 1
|
| 212 |
+
continue
|
| 213 |
+
elif "OFF-TARGET MATRICES" in line:
|
| 214 |
+
index = i
|
| 215 |
+
while "-----" not in line:
|
| 216 |
+
if "MATRIX:" in line:
|
| 217 |
+
retList_off.append(line.split("MATRIX:")[-1].strip()) ### Append name of scoring data to off-target name list
|
| 218 |
+
line = lines[index+1]
|
| 219 |
+
index += 1
|
| 220 |
+
else:
|
| 221 |
+
line = lines[index+1]
|
| 222 |
+
index += 1
|
| 223 |
+
continue
|
| 224 |
+
else:
|
| 225 |
+
continue
|
| 226 |
+
return retList_on, retList_off
|
| 227 |
+
except Exception as e:
|
| 228 |
+
show_error("Error in get_on_off_data() in New Endonuclease.", e)
|
|
@@ -1,17 +1,16 @@
|
|
| 1 |
from ast import Global
|
| 2 |
import os
|
| 3 |
from PyQt5 import QtWidgets, uic, QtGui, QtCore, Qt
|
| 4 |
-
import GlobalSettings
|
| 5 |
from functools import partial
|
| 6 |
-
from Algorithms import SeqTranslate
|
| 7 |
import webbrowser
|
| 8 |
import platform
|
| 9 |
import traceback
|
| 10 |
import math
|
|
|
|
|
|
|
| 11 |
|
| 12 |
-
from ui_utils import center_ui
|
| 13 |
-
|
| 14 |
-
#global logger
|
| 15 |
logger = GlobalSettings.logger
|
| 16 |
|
| 17 |
def iter_except(function, exception):
|
|
@@ -22,13 +21,12 @@ def iter_except(function, exception):
|
|
| 22 |
except exception:
|
| 23 |
return
|
| 24 |
|
| 25 |
-
|
| 26 |
#UI prompt for when the user has finished running jobs in new genome to allow them to choose where the want to proceed
|
| 27 |
class goToPrompt(QtWidgets.QMainWindow):
|
| 28 |
def __init__(self):
|
| 29 |
try:
|
| 30 |
super(goToPrompt, self).__init__()
|
| 31 |
-
uic.loadUi(GlobalSettings.appdir + 'newgenomenavigationpage.ui', self)
|
| 32 |
|
| 33 |
groupbox_style = """
|
| 34 |
QGroupBox:title{subcontrol-origin: margin;
|
|
@@ -39,125 +37,20 @@ class goToPrompt(QtWidgets.QMainWindow):
|
|
| 39 |
font: bold 14pt 'Arial';
|
| 40 |
margin-top: 10px;}"""
|
| 41 |
self.groupBox.setStyleSheet(groupbox_style)
|
| 42 |
-
self
|
| 43 |
self.setWindowTitle("New Genome")
|
| 44 |
self.setWindowIcon(Qt.QIcon(GlobalSettings.appdir + "cas9image.ico"))
|
| 45 |
self.hide()
|
| 46 |
|
| 47 |
except Exception as e:
|
| 48 |
-
|
| 49 |
-
logger.critical(e)
|
| 50 |
-
logger.critical(traceback.format_exc())
|
| 51 |
-
msgBox = QtWidgets.QMessageBox()
|
| 52 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 53 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 54 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 55 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 56 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 57 |
-
msgBox.exec()
|
| 58 |
-
|
| 59 |
-
exit(-1)
|
| 60 |
-
|
| 61 |
-
#scale UI based on current screen
|
| 62 |
-
def scaleUI(self):
|
| 63 |
-
try:
|
| 64 |
-
self.repaint()
|
| 65 |
-
QtWidgets.QApplication.processEvents()
|
| 66 |
-
|
| 67 |
-
screen = self.screen()
|
| 68 |
-
dpi = screen.physicalDotsPerInch()
|
| 69 |
-
width = screen.geometry().width()
|
| 70 |
-
height = screen.geometry().height()
|
| 71 |
-
|
| 72 |
-
# font scaling
|
| 73 |
-
fontSize = 12
|
| 74 |
-
self.fontSize = fontSize
|
| 75 |
-
self.centralWidget().setStyleSheet("font: " + str(fontSize) + "pt 'Arial';")
|
| 76 |
-
|
| 77 |
-
self.adjustSize()
|
| 78 |
-
|
| 79 |
-
currentWidth = self.size().width()
|
| 80 |
-
currentHeight = self.size().height()
|
| 81 |
-
|
| 82 |
-
# window scaling
|
| 83 |
-
# 1920x1080 => 550x200
|
| 84 |
-
scaledWidth = int((width * 575) / 1920)
|
| 85 |
-
scaledHeight = int((height * 175) / 1080)
|
| 86 |
-
|
| 87 |
-
if scaledHeight < currentHeight:
|
| 88 |
-
scaledHeight = currentHeight
|
| 89 |
-
if scaledWidth < currentWidth:
|
| 90 |
-
scaledWidth = currentWidth
|
| 91 |
-
|
| 92 |
-
screen = QtWidgets.QApplication.desktop().screenNumber(QtWidgets.QApplication.desktop().cursor().pos())
|
| 93 |
-
centerPoint = QtWidgets.QApplication.desktop().screenGeometry(screen).center()
|
| 94 |
-
x = centerPoint.x()
|
| 95 |
-
y = centerPoint.y()
|
| 96 |
-
x = x - (math.ceil(scaledWidth / 2))
|
| 97 |
-
y = y - (math.ceil(scaledHeight / 2))
|
| 98 |
-
self.setGeometry(x, y, scaledWidth, scaledHeight)
|
| 99 |
-
|
| 100 |
-
self.repaint()
|
| 101 |
-
QtWidgets.QApplication.processEvents()
|
| 102 |
-
|
| 103 |
-
except Exception as e:
|
| 104 |
-
logger.critical("Error in scaleUI() in new genome navigation window.")
|
| 105 |
-
logger.critical(e)
|
| 106 |
-
logger.critical(traceback.format_exc())
|
| 107 |
-
msgBox = QtWidgets.QMessageBox()
|
| 108 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 109 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 110 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 111 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 112 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 113 |
-
msgBox.exec()
|
| 114 |
-
|
| 115 |
-
|
| 116 |
-
exit(-1)
|
| 117 |
-
|
| 118 |
-
#center UI on current screen
|
| 119 |
-
def centerUI(self):
|
| 120 |
-
try:
|
| 121 |
-
self.repaint()
|
| 122 |
-
QtWidgets.QApplication.processEvents()
|
| 123 |
-
|
| 124 |
-
#center window on current screen
|
| 125 |
-
width = self.width()
|
| 126 |
-
height = self.height()
|
| 127 |
-
screen = QtWidgets.QApplication.desktop().screenNumber(QtWidgets.QApplication.desktop().cursor().pos())
|
| 128 |
-
centerPoint = QtWidgets.QApplication.desktop().screenGeometry(screen).center()
|
| 129 |
-
x = centerPoint.x()
|
| 130 |
-
y = centerPoint.y()
|
| 131 |
-
x = x - (math.ceil(width / 2))
|
| 132 |
-
y = y - (math.ceil(height / 2))
|
| 133 |
-
self.setGeometry(x, y, width, height)
|
| 134 |
-
|
| 135 |
-
self.repaint()
|
| 136 |
-
QtWidgets.QApplication.processEvents()
|
| 137 |
-
except Exception as e:
|
| 138 |
-
logger.critical("Error in centerUI() in new genome navigation window.")
|
| 139 |
-
logger.critical(e)
|
| 140 |
-
logger.critical(traceback.format_exc())
|
| 141 |
-
msgBox = QtWidgets.QMessageBox()
|
| 142 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 143 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 144 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 145 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 146 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 147 |
-
msgBox.exec()
|
| 148 |
-
|
| 149 |
-
|
| 150 |
-
exit(-1)
|
| 151 |
-
|
| 152 |
|
| 153 |
#New genome class to allow users to generate new CSPR files
|
| 154 |
class NewGenome(QtWidgets.QMainWindow):
|
| 155 |
-
|
| 156 |
-
#init class
|
| 157 |
def __init__(self, info_path):
|
| 158 |
try:
|
| 159 |
super(NewGenome, self).__init__()
|
| 160 |
-
uic.loadUi(GlobalSettings.appdir + 'NewGenome.ui', self)
|
| 161 |
self.setWindowTitle('New Genome')
|
| 162 |
self.setWindowTitle('New Genome')
|
| 163 |
self.info_path = info_path
|
|
@@ -203,7 +96,6 @@ class NewGenome(QtWidgets.QMainWindow):
|
|
| 203 |
self.seqTrans = SeqTranslate()
|
| 204 |
self.exit = False
|
| 205 |
|
| 206 |
-
|
| 207 |
self.first = False
|
| 208 |
#show functionalities on window
|
| 209 |
self.fillEndo()
|
|
@@ -219,7 +111,6 @@ class NewGenome(QtWidgets.QMainWindow):
|
|
| 219 |
self.job_Table.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.AdjustToContents)
|
| 220 |
self.fin_index=0
|
| 221 |
|
| 222 |
-
|
| 223 |
self.mwfg = self.frameGeometry() ##Center window
|
| 224 |
self.cp = QtWidgets.QDesktopWidget().availableGeometry().center() ##Center window
|
| 225 |
self.total_chrom_count = 0
|
|
@@ -227,8 +118,8 @@ class NewGenome(QtWidgets.QMainWindow):
|
|
| 227 |
self.progress = 0
|
| 228 |
|
| 229 |
#toolbar button actions
|
| 230 |
-
self.visit_repo.triggered.connect(
|
| 231 |
-
self.go_ncbi.triggered.connect(
|
| 232 |
|
| 233 |
self.comboBoxEndo.currentIndexChanged.connect(self.changeEndos)
|
| 234 |
|
|
@@ -260,24 +151,10 @@ class NewGenome(QtWidgets.QMainWindow):
|
|
| 260 |
self.strainName.setValidator(input_validator1)
|
| 261 |
self.orgCode.setValidator(input_validator2)
|
| 262 |
|
| 263 |
-
|
| 264 |
-
# scale_ui(self)
|
| 265 |
self.first_show = True
|
| 266 |
-
|
| 267 |
except Exception as e:
|
| 268 |
-
|
| 269 |
-
logger.critical(e)
|
| 270 |
-
logger.critical(traceback.format_exc())
|
| 271 |
-
msgBox = QtWidgets.QMessageBox()
|
| 272 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 273 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 274 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 275 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 276 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 277 |
-
msgBox.exec()
|
| 278 |
-
|
| 279 |
-
|
| 280 |
-
exit(-1)
|
| 281 |
|
| 282 |
def launch_newEndonuclease(self):
|
| 283 |
try:
|
|
@@ -286,17 +163,7 @@ class NewGenome(QtWidgets.QMainWindow):
|
|
| 286 |
GlobalSettings.mainWindow.newEndonuclease.show()
|
| 287 |
GlobalSettings.mainWindow.newEndonuclease.activateWindow()
|
| 288 |
except Exception as e:
|
| 289 |
-
|
| 290 |
-
logger.critical(e)
|
| 291 |
-
logger.critical(traceback.format_exc())
|
| 292 |
-
msgBox = QtWidgets.QMessageBox()
|
| 293 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 294 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 295 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 296 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 297 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 298 |
-
msgBox.exec()
|
| 299 |
-
exit(-1)
|
| 300 |
|
| 301 |
#open the ncbi search tool window
|
| 302 |
def open_ncbi_tool(self):
|
|
@@ -312,21 +179,8 @@ class NewGenome(QtWidgets.QMainWindow):
|
|
| 312 |
GlobalSettings.mainWindow.ncbi.show()
|
| 313 |
GlobalSettings.mainWindow.ncbi.activateWindow()
|
| 314 |
except Exception as e:
|
| 315 |
-
|
| 316 |
-
logger.critical(e)
|
| 317 |
-
logger.critical(traceback.format_exc())
|
| 318 |
-
msgBox = QtWidgets.QMessageBox()
|
| 319 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 320 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 321 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 322 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 323 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 324 |
-
msgBox.exec()
|
| 325 |
-
|
| 326 |
-
|
| 327 |
-
exit(-1)
|
| 328 |
|
| 329 |
-
#remove jobs from queue
|
| 330 |
def remove_from_queue(self):
|
| 331 |
try:
|
| 332 |
while(True):
|
|
@@ -335,19 +189,7 @@ class NewGenome(QtWidgets.QMainWindow):
|
|
| 335 |
break
|
| 336 |
self.job_Table.removeRow(indexes[0].row())
|
| 337 |
except Exception as e:
|
| 338 |
-
|
| 339 |
-
logger.critical(e)
|
| 340 |
-
logger.critical(traceback.format_exc())
|
| 341 |
-
msgBox = QtWidgets.QMessageBox()
|
| 342 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 343 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 344 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 345 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 346 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 347 |
-
msgBox.exec()
|
| 348 |
-
|
| 349 |
-
|
| 350 |
-
exit(-1)
|
| 351 |
|
| 352 |
#prompt user with file browser to select fasta/fna files
|
| 353 |
def selectFasta(self):
|
|
@@ -356,33 +198,18 @@ class NewGenome(QtWidgets.QMainWindow):
|
|
| 356 |
myFile = QtWidgets.QFileDialog.getOpenFileName(filed, "Choose a File")
|
| 357 |
if (myFile[0] != ""):
|
| 358 |
if not myFile[0].endswith(".fa") and not myFile[0].endswith(".fna") and not myFile[0].endswith(".fasta"):
|
| 359 |
-
|
| 360 |
-
|
| 361 |
-
|
| 362 |
-
|
| 363 |
-
|
| 364 |
-
|
| 365 |
-
msgBox.exec()
|
| 366 |
-
|
| 367 |
return
|
| 368 |
else:
|
| 369 |
self.file = myFile[0]
|
| 370 |
self.selectedFile.setText(str(myFile[0]))
|
| 371 |
-
|
| 372 |
except Exception as e:
|
| 373 |
-
|
| 374 |
-
logger.critical(e)
|
| 375 |
-
logger.critical(traceback.format_exc())
|
| 376 |
-
msgBox = QtWidgets.QMessageBox()
|
| 377 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 378 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 379 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 380 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 381 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 382 |
-
msgBox.exec()
|
| 383 |
-
|
| 384 |
-
|
| 385 |
-
exit(-1)
|
| 386 |
|
| 387 |
#submit jobs to queue
|
| 388 |
def submit(self):
|
|
@@ -393,15 +220,13 @@ class NewGenome(QtWidgets.QMainWindow):
|
|
| 393 |
if len(self.file) == 0:
|
| 394 |
warning = warning + "You need to select a file."
|
| 395 |
if len(warning) != 0:
|
| 396 |
-
|
| 397 |
-
|
| 398 |
-
|
| 399 |
-
|
| 400 |
-
|
| 401 |
-
|
| 402 |
-
msgBox.exec()
|
| 403 |
return
|
| 404 |
-
|
| 405 |
if len(self.strainName.text()) == 0:
|
| 406 |
warning = warning + "\nIt is recommended to include the organism's subspecies/strain."
|
| 407 |
if len(self.orgCode.text()) == 0:
|
|
@@ -419,8 +244,6 @@ class NewGenome(QtWidgets.QMainWindow):
|
|
| 419 |
if msgBox.result() == QtWidgets.QMessageBox.No:
|
| 420 |
return
|
| 421 |
|
| 422 |
-
|
| 423 |
-
|
| 424 |
#endo, pam, repeats, directionality, five length, seed length, three length, orgcode, output path, CASPERinfo path, fna path, orgName, notes, on target matrix
|
| 425 |
args = self.Endos[self.comboBoxEndo.currentText()][0]
|
| 426 |
args += " " + self.Endos[self.comboBoxEndo.currentText()][1]
|
|
@@ -458,14 +281,12 @@ class NewGenome(QtWidgets.QMainWindow):
|
|
| 458 |
|
| 459 |
tmp = self.orgName.text()+ " " + self.strainName.text() + " " + self.Endos[self.comboBoxEndo.currentText()][0] + " " + self.orgCode.text()
|
| 460 |
if tmp in self.check_strings:
|
| 461 |
-
|
| 462 |
-
|
| 463 |
-
|
| 464 |
-
|
| 465 |
-
|
| 466 |
-
|
| 467 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Ok)
|
| 468 |
-
msgBox.exec()
|
| 469 |
return
|
| 470 |
name = self.orgCode.text() + "_" + str(self.Endos[self.comboBoxEndo.currentText()][0])
|
| 471 |
rowPosition = self.job_Table.rowCount()
|
|
@@ -476,19 +297,7 @@ class NewGenome(QtWidgets.QMainWindow):
|
|
| 476 |
self.check_strings.append(tmp)
|
| 477 |
self.JobsQueue.append(args)
|
| 478 |
except Exception as e:
|
| 479 |
-
|
| 480 |
-
logger.critical(e)
|
| 481 |
-
logger.critical(traceback.format_exc())
|
| 482 |
-
msgBox = QtWidgets.QMessageBox()
|
| 483 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 484 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 485 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 486 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 487 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 488 |
-
msgBox.exec()
|
| 489 |
-
|
| 490 |
-
|
| 491 |
-
exit(-1)
|
| 492 |
|
| 493 |
#fill the endo dropdown
|
| 494 |
def fillEndo(self):
|
|
@@ -535,19 +344,7 @@ class NewGenome(QtWidgets.QMainWindow):
|
|
| 535 |
#reconnect signal
|
| 536 |
self.comboBoxEndo.currentIndexChanged.connect(self.changeEndos)
|
| 537 |
except Exception as e:
|
| 538 |
-
|
| 539 |
-
logger.critical(e)
|
| 540 |
-
logger.critical(traceback.format_exc())
|
| 541 |
-
msgBox = QtWidgets.QMessageBox()
|
| 542 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 543 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 544 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 545 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 546 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 547 |
-
msgBox.exec()
|
| 548 |
-
|
| 549 |
-
|
| 550 |
-
exit(-1)
|
| 551 |
|
| 552 |
#event handler for endo changing - update endo length data
|
| 553 |
def changeEndos(self):
|
|
@@ -557,19 +354,7 @@ class NewGenome(QtWidgets.QMainWindow):
|
|
| 557 |
self.five_length.setText(self.Endos[key][2])
|
| 558 |
self.three_length.setText(self.Endos[key][4])
|
| 559 |
except Exception as e:
|
| 560 |
-
|
| 561 |
-
logger.critical(e)
|
| 562 |
-
logger.critical(traceback.format_exc())
|
| 563 |
-
msgBox = QtWidgets.QMessageBox()
|
| 564 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 565 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 566 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 567 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 568 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 569 |
-
msgBox.exec()
|
| 570 |
-
|
| 571 |
-
|
| 572 |
-
exit(-1)
|
| 573 |
|
| 574 |
#check if endo is 3' or 5'
|
| 575 |
def endo_settings(self):
|
|
@@ -580,19 +365,7 @@ class NewGenome(QtWidgets.QMainWindow):
|
|
| 580 |
elif int(self.seqTrans.endo_info[self.Endos[self.comboBoxEndo.currentText()][0]][3]) == 5:
|
| 581 |
self.pamBox.setChecked(1)
|
| 582 |
except Exception as e:
|
| 583 |
-
|
| 584 |
-
logger.critical(e)
|
| 585 |
-
logger.critical(traceback.format_exc())
|
| 586 |
-
msgBox = QtWidgets.QMessageBox()
|
| 587 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 588 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 589 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 590 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 591 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 592 |
-
msgBox.exec()
|
| 593 |
-
|
| 594 |
-
|
| 595 |
-
exit(-1)
|
| 596 |
|
| 597 |
#wrapper for running jobs
|
| 598 |
def run_jobs_wrapper(self):
|
|
@@ -605,19 +378,7 @@ class NewGenome(QtWidgets.QMainWindow):
|
|
| 605 |
self.indexes.append(index.row())
|
| 606 |
self.run_job()
|
| 607 |
except Exception as e:
|
| 608 |
-
|
| 609 |
-
logger.critical(e)
|
| 610 |
-
logger.critical(traceback.format_exc())
|
| 611 |
-
msgBox = QtWidgets.QMessageBox()
|
| 612 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 613 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 614 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 615 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 616 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 617 |
-
msgBox.exec()
|
| 618 |
-
|
| 619 |
-
|
| 620 |
-
exit(-1)
|
| 621 |
|
| 622 |
#run job in queue
|
| 623 |
def run_job(self):
|
|
@@ -680,28 +441,14 @@ class NewGenome(QtWidgets.QMainWindow):
|
|
| 680 |
self.process.readyReadStandardOutput.connect(partial(output_stdout, self.process))
|
| 681 |
self.process.start(program)
|
| 682 |
else:
|
| 683 |
-
|
| 684 |
-
|
| 685 |
-
|
| 686 |
-
|
| 687 |
-
|
| 688 |
-
|
| 689 |
-
msgBox.exec()
|
| 690 |
-
|
| 691 |
except Exception as e:
|
| 692 |
-
|
| 693 |
-
logger.critical(e)
|
| 694 |
-
logger.critical(traceback.format_exc())
|
| 695 |
-
msgBox = QtWidgets.QMessageBox()
|
| 696 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 697 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 698 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 699 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 700 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 701 |
-
msgBox.exec()
|
| 702 |
-
|
| 703 |
-
|
| 704 |
-
exit(-1)
|
| 705 |
|
| 706 |
#even handler for when jobs finish execution
|
| 707 |
def upon_process_finishing(self):
|
|
@@ -717,23 +464,11 @@ class NewGenome(QtWidgets.QMainWindow):
|
|
| 717 |
self.run_job()
|
| 718 |
else:
|
| 719 |
#prompt user if they want to analyze their new files
|
| 720 |
-
self.goToPrompt
|
| 721 |
self.goToPrompt.show()
|
| 722 |
self.goToPrompt.activateWindow()
|
| 723 |
except Exception as e:
|
| 724 |
-
|
| 725 |
-
logger.critical(e)
|
| 726 |
-
logger.critical(traceback.format_exc())
|
| 727 |
-
msgBox = QtWidgets.QMessageBox()
|
| 728 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 729 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 730 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 731 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 732 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 733 |
-
msgBox.exec()
|
| 734 |
-
|
| 735 |
-
|
| 736 |
-
exit(-1)
|
| 737 |
|
| 738 |
#clear the job table
|
| 739 |
def clear_all(self):
|
|
@@ -754,19 +489,7 @@ class NewGenome(QtWidgets.QMainWindow):
|
|
| 754 |
self.progressBar.setValue(0)
|
| 755 |
self.first = False
|
| 756 |
except Exception as e:
|
| 757 |
-
|
| 758 |
-
logger.critical(e)
|
| 759 |
-
logger.critical(traceback.format_exc())
|
| 760 |
-
msgBox = QtWidgets.QMessageBox()
|
| 761 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 762 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 763 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 764 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 765 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 766 |
-
msgBox.exec()
|
| 767 |
-
|
| 768 |
-
|
| 769 |
-
exit(-1)
|
| 770 |
|
| 771 |
#reset the whole form
|
| 772 |
def reset(self):
|
|
@@ -780,58 +503,8 @@ class NewGenome(QtWidgets.QMainWindow):
|
|
| 780 |
self.output_browser.setText("Waiting for program initiation...")
|
| 781 |
self.file = ""
|
| 782 |
except Exception as e:
|
| 783 |
-
|
| 784 |
-
|
| 785 |
-
logger.critical(traceback.format_exc())
|
| 786 |
-
msgBox = QtWidgets.QMessageBox()
|
| 787 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 788 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 789 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 790 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 791 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 792 |
-
msgBox.exec()
|
| 793 |
-
|
| 794 |
-
|
| 795 |
-
exit(-1)
|
| 796 |
-
|
| 797 |
-
#menu button for launching NCBI web page
|
| 798 |
-
def open_ncbi_web_page(self):
|
| 799 |
-
try:
|
| 800 |
-
webbrowser.open('https://www.ncbi.nlm.nih.gov/', new=2)
|
| 801 |
-
except Exception as e:
|
| 802 |
-
logger.critical("Error in open_ncbi_web_page() in New Genome.")
|
| 803 |
-
logger.critical(e)
|
| 804 |
-
logger.critical(traceback.format_exc())
|
| 805 |
-
msgBox = QtWidgets.QMessageBox()
|
| 806 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 807 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 808 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 809 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 810 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 811 |
-
msgBox.exec()
|
| 812 |
-
|
| 813 |
-
|
| 814 |
-
exit(-1)
|
| 815 |
-
|
| 816 |
-
#menu button for launching github repo
|
| 817 |
-
def visit_repo_func(self):
|
| 818 |
-
try:
|
| 819 |
-
webbrowser.open('https://github.com/TrinhLab/CASPERapp')
|
| 820 |
-
except Exception as e:
|
| 821 |
-
logger.critical("Error in visit_repo_func() in New Genome.")
|
| 822 |
-
logger.critical(e)
|
| 823 |
-
logger.critical(traceback.format_exc())
|
| 824 |
-
msgBox = QtWidgets.QMessageBox()
|
| 825 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 826 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 827 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 828 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 829 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 830 |
-
msgBox.exec()
|
| 831 |
-
|
| 832 |
-
|
| 833 |
-
exit(-1)
|
| 834 |
-
|
| 835 |
#event handler for user wanting to close the window
|
| 836 |
def closeEvent(self, event):
|
| 837 |
try:
|
|
@@ -861,7 +534,6 @@ class NewGenome(QtWidgets.QMainWindow):
|
|
| 861 |
else:
|
| 862 |
self.exit = False
|
| 863 |
event.accept()
|
| 864 |
-
|
| 865 |
else:
|
| 866 |
self.process.kill()
|
| 867 |
self.clear_all()
|
|
@@ -881,19 +553,7 @@ class NewGenome(QtWidgets.QMainWindow):
|
|
| 881 |
GlobalSettings.mainWindow.show()
|
| 882 |
event.accept()
|
| 883 |
except Exception as e:
|
| 884 |
-
|
| 885 |
-
logger.critical(e)
|
| 886 |
-
logger.critical(traceback.format_exc())
|
| 887 |
-
msgBox = QtWidgets.QMessageBox()
|
| 888 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 889 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 890 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 891 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 892 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 893 |
-
msgBox.exec()
|
| 894 |
-
|
| 895 |
-
|
| 896 |
-
exit(-1)
|
| 897 |
|
| 898 |
#event handler for user wanting to go to Main once jobs complete
|
| 899 |
def continue_to_main(self):
|
|
@@ -918,11 +578,9 @@ class NewGenome(QtWidgets.QMainWindow):
|
|
| 918 |
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.No)
|
| 919 |
msgBox.exec()
|
| 920 |
|
| 921 |
-
|
| 922 |
if (msgBox.result() == QtWidgets.QMessageBox.Yes):
|
| 923 |
self.exit = True
|
| 924 |
self.close()
|
| 925 |
-
|
| 926 |
else:
|
| 927 |
self.process.kill()
|
| 928 |
self.clear_all()
|
|
@@ -943,19 +601,7 @@ class NewGenome(QtWidgets.QMainWindow):
|
|
| 943 |
GlobalSettings.mainWindow.show()
|
| 944 |
self.hide()
|
| 945 |
except Exception as e:
|
| 946 |
-
|
| 947 |
-
logger.critical(e)
|
| 948 |
-
logger.critical(traceback.format_exc())
|
| 949 |
-
msgBox = QtWidgets.QMessageBox()
|
| 950 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 951 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 952 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 953 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 954 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 955 |
-
msgBox.exec()
|
| 956 |
-
|
| 957 |
-
|
| 958 |
-
exit(-1)
|
| 959 |
|
| 960 |
#event handler for user wanting to go to multi-targeting once jobs complete
|
| 961 |
def continue_to_MT(self):
|
|
@@ -1007,19 +653,7 @@ class NewGenome(QtWidgets.QMainWindow):
|
|
| 1007 |
GlobalSettings.MTWin.show()
|
| 1008 |
self.hide()
|
| 1009 |
except Exception as e:
|
| 1010 |
-
|
| 1011 |
-
logger.critical(e)
|
| 1012 |
-
logger.critical(traceback.format_exc())
|
| 1013 |
-
msgBox = QtWidgets.QMessageBox()
|
| 1014 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 1015 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 1016 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 1017 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 1018 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 1019 |
-
msgBox.exec()
|
| 1020 |
-
|
| 1021 |
-
|
| 1022 |
-
exit(-1)
|
| 1023 |
|
| 1024 |
#event handler for user wanting to go to population analysis once jobs complete
|
| 1025 |
def continue_to_pop(self):
|
|
@@ -1068,16 +702,4 @@ class NewGenome(QtWidgets.QMainWindow):
|
|
| 1068 |
GlobalSettings.pop_Analysis.show()
|
| 1069 |
self.hide()
|
| 1070 |
except Exception as e:
|
| 1071 |
-
|
| 1072 |
-
logger.critical(e)
|
| 1073 |
-
logger.critical(traceback.format_exc())
|
| 1074 |
-
msgBox = QtWidgets.QMessageBox()
|
| 1075 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 1076 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 1077 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 1078 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 1079 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 1080 |
-
msgBox.exec()
|
| 1081 |
-
|
| 1082 |
-
|
| 1083 |
-
exit(-1)
|
|
|
|
| 1 |
from ast import Global
|
| 2 |
import os
|
| 3 |
from PyQt5 import QtWidgets, uic, QtGui, QtCore, Qt
|
| 4 |
+
import models.GlobalSettings as GlobalSettings
|
| 5 |
from functools import partial
|
| 6 |
+
from utils.Algorithms import SeqTranslate
|
| 7 |
import webbrowser
|
| 8 |
import platform
|
| 9 |
import traceback
|
| 10 |
import math
|
| 11 |
+
from utils.ui import show_message, show_error, scale_ui, center_ui
|
| 12 |
+
from utils.web import ncbi_page, repo_page
|
| 13 |
|
|
|
|
|
|
|
|
|
|
| 14 |
logger = GlobalSettings.logger
|
| 15 |
|
| 16 |
def iter_except(function, exception):
|
|
|
|
| 21 |
except exception:
|
| 22 |
return
|
| 23 |
|
|
|
|
| 24 |
#UI prompt for when the user has finished running jobs in new genome to allow them to choose where the want to proceed
|
| 25 |
class goToPrompt(QtWidgets.QMainWindow):
|
| 26 |
def __init__(self):
|
| 27 |
try:
|
| 28 |
super(goToPrompt, self).__init__()
|
| 29 |
+
uic.loadUi(GlobalSettings.appdir + 'ui/newgenomenavigationpage.ui', self)
|
| 30 |
|
| 31 |
groupbox_style = """
|
| 32 |
QGroupBox:title{subcontrol-origin: margin;
|
|
|
|
| 37 |
font: bold 14pt 'Arial';
|
| 38 |
margin-top: 10px;}"""
|
| 39 |
self.groupBox.setStyleSheet(groupbox_style)
|
| 40 |
+
scale_ui(self, custom_scale_width=575, custom_scale_height=175)
|
| 41 |
self.setWindowTitle("New Genome")
|
| 42 |
self.setWindowIcon(Qt.QIcon(GlobalSettings.appdir + "cas9image.ico"))
|
| 43 |
self.hide()
|
| 44 |
|
| 45 |
except Exception as e:
|
| 46 |
+
show_error("Unable to initialize goToPrompt class in New Genome.", e)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 47 |
|
| 48 |
#New genome class to allow users to generate new CSPR files
|
| 49 |
class NewGenome(QtWidgets.QMainWindow):
|
|
|
|
|
|
|
| 50 |
def __init__(self, info_path):
|
| 51 |
try:
|
| 52 |
super(NewGenome, self).__init__()
|
| 53 |
+
uic.loadUi(GlobalSettings.appdir + 'ui/NewGenome.ui', self)
|
| 54 |
self.setWindowTitle('New Genome')
|
| 55 |
self.setWindowTitle('New Genome')
|
| 56 |
self.info_path = info_path
|
|
|
|
| 96 |
self.seqTrans = SeqTranslate()
|
| 97 |
self.exit = False
|
| 98 |
|
|
|
|
| 99 |
self.first = False
|
| 100 |
#show functionalities on window
|
| 101 |
self.fillEndo()
|
|
|
|
| 111 |
self.job_Table.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.AdjustToContents)
|
| 112 |
self.fin_index=0
|
| 113 |
|
|
|
|
| 114 |
self.mwfg = self.frameGeometry() ##Center window
|
| 115 |
self.cp = QtWidgets.QDesktopWidget().availableGeometry().center() ##Center window
|
| 116 |
self.total_chrom_count = 0
|
|
|
|
| 118 |
self.progress = 0
|
| 119 |
|
| 120 |
#toolbar button actions
|
| 121 |
+
self.visit_repo.triggered.connect(repo_page)
|
| 122 |
+
self.go_ncbi.triggered.connect(ncbi_page)
|
| 123 |
|
| 124 |
self.comboBoxEndo.currentIndexChanged.connect(self.changeEndos)
|
| 125 |
|
|
|
|
| 151 |
self.strainName.setValidator(input_validator1)
|
| 152 |
self.orgCode.setValidator(input_validator2)
|
| 153 |
|
| 154 |
+
scale_ui(self, custom_scale_width=850, custom_scale_height=750)
|
|
|
|
| 155 |
self.first_show = True
|
|
|
|
| 156 |
except Exception as e:
|
| 157 |
+
show_error("Error initializing New Genome class.", e)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 158 |
|
| 159 |
def launch_newEndonuclease(self):
|
| 160 |
try:
|
|
|
|
| 163 |
GlobalSettings.mainWindow.newEndonuclease.show()
|
| 164 |
GlobalSettings.mainWindow.newEndonuclease.activateWindow()
|
| 165 |
except Exception as e:
|
| 166 |
+
show_error("Error in launch_newEndonuclease() in New Genome.", e)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 167 |
|
| 168 |
#open the ncbi search tool window
|
| 169 |
def open_ncbi_tool(self):
|
|
|
|
| 179 |
GlobalSettings.mainWindow.ncbi.show()
|
| 180 |
GlobalSettings.mainWindow.ncbi.activateWindow()
|
| 181 |
except Exception as e:
|
| 182 |
+
show_error("Error in open_ncbi_tool() in New Genome.", e)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 183 |
|
|
|
|
| 184 |
def remove_from_queue(self):
|
| 185 |
try:
|
| 186 |
while(True):
|
|
|
|
| 189 |
break
|
| 190 |
self.job_Table.removeRow(indexes[0].row())
|
| 191 |
except Exception as e:
|
| 192 |
+
show_error("Error in remove_from_queue() in New Genome.", e)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 193 |
|
| 194 |
#prompt user with file browser to select fasta/fna files
|
| 195 |
def selectFasta(self):
|
|
|
|
| 198 |
myFile = QtWidgets.QFileDialog.getOpenFileName(filed, "Choose a File")
|
| 199 |
if (myFile[0] != ""):
|
| 200 |
if not myFile[0].endswith(".fa") and not myFile[0].endswith(".fna") and not myFile[0].endswith(".fasta"):
|
| 201 |
+
show_message(
|
| 202 |
+
fontSize=12,
|
| 203 |
+
icon=QtWidgets.QMessageBox.Icon.Critical,
|
| 204 |
+
title="File Selection Error",
|
| 205 |
+
message="You have selected an incorrect type of file. Please choose a FASTA/FNA file."
|
| 206 |
+
)
|
|
|
|
|
|
|
| 207 |
return
|
| 208 |
else:
|
| 209 |
self.file = myFile[0]
|
| 210 |
self.selectedFile.setText(str(myFile[0]))
|
|
|
|
| 211 |
except Exception as e:
|
| 212 |
+
show_error("Error in selectFasta() in New Genome.", e)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 213 |
|
| 214 |
#submit jobs to queue
|
| 215 |
def submit(self):
|
|
|
|
| 220 |
if len(self.file) == 0:
|
| 221 |
warning = warning + "You need to select a file."
|
| 222 |
if len(warning) != 0:
|
| 223 |
+
show_message(
|
| 224 |
+
fontSize=12,
|
| 225 |
+
icon=QtWidgets.QMessageBox.Icon.Critical,
|
| 226 |
+
title="Required Information",
|
| 227 |
+
message=warning
|
| 228 |
+
)
|
|
|
|
| 229 |
return
|
|
|
|
| 230 |
if len(self.strainName.text()) == 0:
|
| 231 |
warning = warning + "\nIt is recommended to include the organism's subspecies/strain."
|
| 232 |
if len(self.orgCode.text()) == 0:
|
|
|
|
| 244 |
if msgBox.result() == QtWidgets.QMessageBox.No:
|
| 245 |
return
|
| 246 |
|
|
|
|
|
|
|
| 247 |
#endo, pam, repeats, directionality, five length, seed length, three length, orgcode, output path, CASPERinfo path, fna path, orgName, notes, on target matrix
|
| 248 |
args = self.Endos[self.comboBoxEndo.currentText()][0]
|
| 249 |
args += " " + self.Endos[self.comboBoxEndo.currentText()][1]
|
|
|
|
| 281 |
|
| 282 |
tmp = self.orgName.text()+ " " + self.strainName.text() + " " + self.Endos[self.comboBoxEndo.currentText()][0] + " " + self.orgCode.text()
|
| 283 |
if tmp in self.check_strings:
|
| 284 |
+
show_message(
|
| 285 |
+
fontSize=12,
|
| 286 |
+
icon=QtWidgets.QMessageBox.Icon.Critical,
|
| 287 |
+
title="Duplicate Entry",
|
| 288 |
+
message="You have submitted a duplicate entry. Consider changing the organism code or strain name to differentiate closely related strains."
|
| 289 |
+
)
|
|
|
|
|
|
|
| 290 |
return
|
| 291 |
name = self.orgCode.text() + "_" + str(self.Endos[self.comboBoxEndo.currentText()][0])
|
| 292 |
rowPosition = self.job_Table.rowCount()
|
|
|
|
| 297 |
self.check_strings.append(tmp)
|
| 298 |
self.JobsQueue.append(args)
|
| 299 |
except Exception as e:
|
| 300 |
+
show_error("Error in submit() in New Genome.", e)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 301 |
|
| 302 |
#fill the endo dropdown
|
| 303 |
def fillEndo(self):
|
|
|
|
| 344 |
#reconnect signal
|
| 345 |
self.comboBoxEndo.currentIndexChanged.connect(self.changeEndos)
|
| 346 |
except Exception as e:
|
| 347 |
+
show_error("Error in fillEndo() in New Genome.", e)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 348 |
|
| 349 |
#event handler for endo changing - update endo length data
|
| 350 |
def changeEndos(self):
|
|
|
|
| 354 |
self.five_length.setText(self.Endos[key][2])
|
| 355 |
self.three_length.setText(self.Endos[key][4])
|
| 356 |
except Exception as e:
|
| 357 |
+
show_error("Error in changeEndos() in New Genome.", e)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 358 |
|
| 359 |
#check if endo is 3' or 5'
|
| 360 |
def endo_settings(self):
|
|
|
|
| 365 |
elif int(self.seqTrans.endo_info[self.Endos[self.comboBoxEndo.currentText()][0]][3]) == 5:
|
| 366 |
self.pamBox.setChecked(1)
|
| 367 |
except Exception as e:
|
| 368 |
+
show_error("Error in endo_settings() in New Genome.", e)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 369 |
|
| 370 |
#wrapper for running jobs
|
| 371 |
def run_jobs_wrapper(self):
|
|
|
|
| 378 |
self.indexes.append(index.row())
|
| 379 |
self.run_job()
|
| 380 |
except Exception as e:
|
| 381 |
+
show_error("Error in run_jobs_wrapper() in New Genome.", e)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 382 |
|
| 383 |
#run job in queue
|
| 384 |
def run_job(self):
|
|
|
|
| 441 |
self.process.readyReadStandardOutput.connect(partial(output_stdout, self.process))
|
| 442 |
self.process.start(program)
|
| 443 |
else:
|
| 444 |
+
show_message(
|
| 445 |
+
fontSize=12,
|
| 446 |
+
icon=QtWidgets.QMessageBox.Icon.Critical,
|
| 447 |
+
title="No Jobs To Run",
|
| 448 |
+
message="No jobs are in the queue to run. Please add a job before running."
|
| 449 |
+
)
|
|
|
|
|
|
|
| 450 |
except Exception as e:
|
| 451 |
+
show_error("Error in run_job() in New Genome.", e)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 452 |
|
| 453 |
#even handler for when jobs finish execution
|
| 454 |
def upon_process_finishing(self):
|
|
|
|
| 464 |
self.run_job()
|
| 465 |
else:
|
| 466 |
#prompt user if they want to analyze their new files
|
| 467 |
+
center_ui(self.goToPrompt)
|
| 468 |
self.goToPrompt.show()
|
| 469 |
self.goToPrompt.activateWindow()
|
| 470 |
except Exception as e:
|
| 471 |
+
show_error("Error in upon_process_finishing() in New Genome.", e)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 472 |
|
| 473 |
#clear the job table
|
| 474 |
def clear_all(self):
|
|
|
|
| 489 |
self.progressBar.setValue(0)
|
| 490 |
self.first = False
|
| 491 |
except Exception as e:
|
| 492 |
+
show_error("Error in clear_all() in New Genome.", e)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 493 |
|
| 494 |
#reset the whole form
|
| 495 |
def reset(self):
|
|
|
|
| 503 |
self.output_browser.setText("Waiting for program initiation...")
|
| 504 |
self.file = ""
|
| 505 |
except Exception as e:
|
| 506 |
+
show_error("Error in reset() in New Genome.", e)
|
| 507 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 508 |
#event handler for user wanting to close the window
|
| 509 |
def closeEvent(self, event):
|
| 510 |
try:
|
|
|
|
| 534 |
else:
|
| 535 |
self.exit = False
|
| 536 |
event.accept()
|
|
|
|
| 537 |
else:
|
| 538 |
self.process.kill()
|
| 539 |
self.clear_all()
|
|
|
|
| 553 |
GlobalSettings.mainWindow.show()
|
| 554 |
event.accept()
|
| 555 |
except Exception as e:
|
| 556 |
+
show_error("Error in closeEvent() in New Genome.", e)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 557 |
|
| 558 |
#event handler for user wanting to go to Main once jobs complete
|
| 559 |
def continue_to_main(self):
|
|
|
|
| 578 |
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.No)
|
| 579 |
msgBox.exec()
|
| 580 |
|
|
|
|
| 581 |
if (msgBox.result() == QtWidgets.QMessageBox.Yes):
|
| 582 |
self.exit = True
|
| 583 |
self.close()
|
|
|
|
| 584 |
else:
|
| 585 |
self.process.kill()
|
| 586 |
self.clear_all()
|
|
|
|
| 601 |
GlobalSettings.mainWindow.show()
|
| 602 |
self.hide()
|
| 603 |
except Exception as e:
|
| 604 |
+
show_error("Error in continue_to_main() in New Genome.", e)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 605 |
|
| 606 |
#event handler for user wanting to go to multi-targeting once jobs complete
|
| 607 |
def continue_to_MT(self):
|
|
|
|
| 653 |
GlobalSettings.MTWin.show()
|
| 654 |
self.hide()
|
| 655 |
except Exception as e:
|
| 656 |
+
show_error("Error in continue_to_MT() in New Genome.", e)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 657 |
|
| 658 |
#event handler for user wanting to go to population analysis once jobs complete
|
| 659 |
def continue_to_pop(self):
|
|
|
|
| 702 |
GlobalSettings.pop_Analysis.show()
|
| 703 |
self.hide()
|
| 704 |
except Exception as e:
|
| 705 |
+
show_error("Error in continue_to_pop() in New Genome.", e)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@@ -0,0 +1,255 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import platform
|
| 3 |
+
import traceback
|
| 4 |
+
import logging
|
| 5 |
+
from PyQt5 import QtGui, QtWidgets, QtCore, uic, Qt
|
| 6 |
+
import models.GlobalSettings as GlobalSettings
|
| 7 |
+
from utils.ui import show_message, show_error, scale_ui
|
| 8 |
+
|
| 9 |
+
logger = GlobalSettings.logger
|
| 10 |
+
|
| 11 |
+
class StartupWindow(QtWidgets.QMainWindow):
|
| 12 |
+
def __init__(self):
|
| 13 |
+
try:
|
| 14 |
+
super(StartupWindow, self).__init__()
|
| 15 |
+
try:
|
| 16 |
+
uic.loadUi(GlobalSettings.appdir + 'ui/startupCASPER.ui', self)
|
| 17 |
+
self.setWindowIcon(QtGui.QIcon(GlobalSettings.appdir + "cas9image.png"))
|
| 18 |
+
except Exception as e:
|
| 19 |
+
show_error("Unable to load UX files for Startup Window.", e)
|
| 20 |
+
|
| 21 |
+
#set "Main" button to be the default highlighted button on startup
|
| 22 |
+
self.goToMain.setDefault(True)
|
| 23 |
+
|
| 24 |
+
#get current directory, and update based on current operating system
|
| 25 |
+
self.currentDirectory = os.getcwd()
|
| 26 |
+
self.databaseDirectory = self.loadDatabaseDirectory()
|
| 27 |
+
GlobalSettings.CSPR_DB = self.databaseDirectory
|
| 28 |
+
if platform.system() == "Windows":
|
| 29 |
+
GlobalSettings.CSPR_DB = GlobalSettings.CSPR_DB.replace("/","\\")
|
| 30 |
+
else:
|
| 31 |
+
GlobalSettings.CSPR_DB = GlobalSettings.CSPR_DB.replace("\\","/")
|
| 32 |
+
|
| 33 |
+
#setup event handlers for startup buttons
|
| 34 |
+
self.currentDirText.setText(self.databaseDirectory)
|
| 35 |
+
self.changeDir.clicked.connect(self.change_directory)
|
| 36 |
+
self.goToMain.clicked.connect(self.launchMainWindow)
|
| 37 |
+
self.goToNewGenome.clicked.connect(self.launchNewGenome)
|
| 38 |
+
|
| 39 |
+
self.setWindowTitle("CASPER")
|
| 40 |
+
self.setWindowIcon(Qt.QIcon(GlobalSettings.appdir + "cas9image.ico"))
|
| 41 |
+
|
| 42 |
+
scale_ui(self, custom_scale_width=1150, custom_scale_height=650)
|
| 43 |
+
|
| 44 |
+
except Exception as e:
|
| 45 |
+
show_error("Error initializing StartupWindow class.", e)
|
| 46 |
+
|
| 47 |
+
#event handler for user clicking the "Change..." button - used for changing CASPER database directory
|
| 48 |
+
def change_directory(self):
|
| 49 |
+
try:
|
| 50 |
+
# Launch OS file browser
|
| 51 |
+
newDirectory = QtWidgets.QFileDialog.getExistingDirectory(
|
| 52 |
+
self, "Open a folder...", self.databaseDirectory, QtWidgets.QFileDialog.ShowDirsOnly)
|
| 53 |
+
|
| 54 |
+
# Check if selected path is a directory in the system
|
| 55 |
+
if not os.path.isdir(newDirectory):
|
| 56 |
+
show_message(
|
| 57 |
+
fontSize=self.fontSize,
|
| 58 |
+
icon=QtWidgets.QMessageBox.Icon.Critical,
|
| 59 |
+
title="Not a directory",
|
| 60 |
+
message="The directory you selected does not exist.",
|
| 61 |
+
)
|
| 62 |
+
return
|
| 63 |
+
|
| 64 |
+
# Ensure directory contains correct filepath format based on OS
|
| 65 |
+
newDirectory = newDirectory.replace("/", "\\") if platform.system() == "Windows" else newDirectory.replace("\\", "/")
|
| 66 |
+
|
| 67 |
+
# Update text edit showing the current selected database directory
|
| 68 |
+
self.currentDirText.setText(newDirectory)
|
| 69 |
+
|
| 70 |
+
# Update CASPER database directories
|
| 71 |
+
self.databaseDirectory = newDirectory
|
| 72 |
+
GlobalSettings.CSPR_DB = newDirectory
|
| 73 |
+
|
| 74 |
+
except Exception as e:
|
| 75 |
+
show_error("change_directory() in startup window", e)
|
| 76 |
+
|
| 77 |
+
#function for loading the default database directory specified in CASPERinfo
|
| 78 |
+
#returns: default database parsed from CASPERinfo
|
| 79 |
+
def loadDatabaseDirectory(self):
|
| 80 |
+
casperInfoPath = os.path.join(GlobalSettings.appdir, "CASPERinfo")
|
| 81 |
+
defaultDirectory = "Where would you like to store CASPER database files?" # Default message if directory not found
|
| 82 |
+
|
| 83 |
+
try:
|
| 84 |
+
with open(casperInfoPath, 'r') as file:
|
| 85 |
+
for line in file:
|
| 86 |
+
if 'DIRECTORY:' in line:
|
| 87 |
+
defaultDirectory = line.strip().replace("DIRECTORY:", "").strip()
|
| 88 |
+
break
|
| 89 |
+
|
| 90 |
+
# Ensure the directory path is formatted correctly based on the operating system
|
| 91 |
+
if platform.system() == "Windows":
|
| 92 |
+
defaultDirectory = defaultDirectory.replace("/", "\\")
|
| 93 |
+
else:
|
| 94 |
+
defaultDirectory = defaultDirectory.replace("\\", "/")
|
| 95 |
+
|
| 96 |
+
logger.debug("Successfully parsed CASPERinfo for default database directory.")
|
| 97 |
+
return defaultDirectory
|
| 98 |
+
|
| 99 |
+
except Exception as e:
|
| 100 |
+
show_error(f"Error reading {casperInfoPath}: {e}", e)
|
| 101 |
+
|
| 102 |
+
return defaultDirectory
|
| 103 |
+
|
| 104 |
+
#function for saving the currently selected database directory to CASPERinfo to be the new default value on startup
|
| 105 |
+
def saveDatabaseDirectory(self):
|
| 106 |
+
try:
|
| 107 |
+
#variable to hold the CASPERinfo data with new default directory change
|
| 108 |
+
CASPERInfoNewData = ""
|
| 109 |
+
|
| 110 |
+
#new default directory string for CASPERinfo
|
| 111 |
+
newDefaultDirectory = "DIRECTORY:" + str(self.databaseDirectory)
|
| 112 |
+
|
| 113 |
+
#open CASPERinfo file to read in the files data and add in new change
|
| 114 |
+
try:
|
| 115 |
+
CASPERInfo = open(GlobalSettings.appdir + "CASPERinfo", 'r+')
|
| 116 |
+
CASPERinfoData = CASPERInfo.read()
|
| 117 |
+
CASPERinfoData = CASPERinfoData.split('\n')
|
| 118 |
+
for line in CASPERinfoData:
|
| 119 |
+
#if directory line found, use new default directory string instead
|
| 120 |
+
if 'DIRECTORY:' in line:
|
| 121 |
+
CASPERInfoNewData = CASPERInfoNewData + "\n" + newDefaultDirectory
|
| 122 |
+
else:
|
| 123 |
+
CASPERInfoNewData = CASPERInfoNewData + "\n" + line
|
| 124 |
+
CASPERInfoNewData = CASPERInfoNewData[1:]
|
| 125 |
+
|
| 126 |
+
#close CASPERinfo
|
| 127 |
+
CASPERInfo.close()
|
| 128 |
+
|
| 129 |
+
#re-open the file and re-write it with current changes
|
| 130 |
+
CASPERInfo = open(GlobalSettings.appdir + "CASPERinfo", 'w+')
|
| 131 |
+
CASPERInfo.write(CASPERInfoNewData)
|
| 132 |
+
CASPERInfo.close()
|
| 133 |
+
logger.debug("Successfully updated CASPERinfo with new default database directory.")
|
| 134 |
+
except Exception as e:
|
| 135 |
+
show_error("Unable to write to CASPERinfo file to update database directory.", e)
|
| 136 |
+
except Exception as e:
|
| 137 |
+
show_error("Error in saveDatabaseDirectory() in startup window.", e)
|
| 138 |
+
|
| 139 |
+
# Event handler for user clicking the "New Genome" button - used for launching New Genome
|
| 140 |
+
def launchNewGenome(self):
|
| 141 |
+
try:
|
| 142 |
+
# Make sure database directory variable is up-to-date based on what the user has in the text edit
|
| 143 |
+
self.databaseDirectory = str(self.currentDirText.text())
|
| 144 |
+
|
| 145 |
+
if not os.path.isdir(self.databaseDirectory):
|
| 146 |
+
show_message(
|
| 147 |
+
fontSize=12,
|
| 148 |
+
icon=QtWidgets.QMessageBox.Icon.Critical,
|
| 149 |
+
title="Not a directory",
|
| 150 |
+
message="The directory you selected does not exist.",
|
| 151 |
+
)
|
| 152 |
+
return
|
| 153 |
+
|
| 154 |
+
# Change directories to the specified database directory provided
|
| 155 |
+
os.chdir(self.databaseDirectory)
|
| 156 |
+
|
| 157 |
+
# Write out the database directory to CASPERinfo to be the new default loaded value
|
| 158 |
+
self.saveDatabaseDirectory()
|
| 159 |
+
|
| 160 |
+
# Update global database variable
|
| 161 |
+
GlobalSettings.CSPR_DB = self.databaseDirectory
|
| 162 |
+
|
| 163 |
+
# Create app directories
|
| 164 |
+
initialize_app_directories()
|
| 165 |
+
|
| 166 |
+
# Launch New Genome window
|
| 167 |
+
self.launch_new_genome()
|
| 168 |
+
|
| 169 |
+
self.close()
|
| 170 |
+
except Exception as e:
|
| 171 |
+
show_error("launchNewGenome() in startup window", e)
|
| 172 |
+
|
| 173 |
+
def launch_new_genome(self):
|
| 174 |
+
try:
|
| 175 |
+
GlobalSettings.mainWindow.launch_newGenome()
|
| 176 |
+
logger.debug("Successfully initialized New Genome in startup window.")
|
| 177 |
+
except Exception as e:
|
| 178 |
+
show_error("launch_new_genome() in startup window", e)
|
| 179 |
+
|
| 180 |
+
# Event handler for user clicking "Main Program" button - used to launch Main Window
|
| 181 |
+
def launchMainWindow(self):
|
| 182 |
+
try:
|
| 183 |
+
# Make sure database directory variable is up-to-date based on what the user has in the text edit
|
| 184 |
+
self.databaseDirectory = str(self.currentDirText.text())
|
| 185 |
+
|
| 186 |
+
# Make sure the path is a valid path before launching New Genome
|
| 187 |
+
if not os.path.isdir(self.databaseDirectory):
|
| 188 |
+
show_message(
|
| 189 |
+
fontSize=12,
|
| 190 |
+
icon=QtWidgets.QMessageBox.Icon.Critical,
|
| 191 |
+
title="Not a directory",
|
| 192 |
+
message="The directory you selected does not exist.",
|
| 193 |
+
)
|
| 194 |
+
return
|
| 195 |
+
|
| 196 |
+
# Check if database directory has CSPR files in it
|
| 197 |
+
if not any(file.endswith(".cspr") for file in os.listdir(self.databaseDirectory)):
|
| 198 |
+
show_message(
|
| 199 |
+
fontSize=12,
|
| 200 |
+
icon=QtWidgets.QMessageBox.Icon.Critical,
|
| 201 |
+
title="Directory is invalid!",
|
| 202 |
+
message="You must select a directory with CSPR Files!",
|
| 203 |
+
)
|
| 204 |
+
return
|
| 205 |
+
|
| 206 |
+
# Change directory to database directory
|
| 207 |
+
os.chdir(self.databaseDirectory)
|
| 208 |
+
|
| 209 |
+
# Update database directory global variable
|
| 210 |
+
GlobalSettings.CSPR_DB = self.databaseDirectory
|
| 211 |
+
|
| 212 |
+
# Save database directory to CASPERinfo
|
| 213 |
+
self.saveDatabaseDirectory()
|
| 214 |
+
|
| 215 |
+
initialize_app_directories()
|
| 216 |
+
|
| 217 |
+
# Fill in organism/endo/annotation dropdown information for main, mulit-targeting, and populatin analysis
|
| 218 |
+
self.load_dropdown_data()
|
| 219 |
+
|
| 220 |
+
# Show main window
|
| 221 |
+
if GlobalSettings.mainWindow.first_show:
|
| 222 |
+
GlobalSettings.mainWindow.first_show = False
|
| 223 |
+
GlobalSettings.mainWindow.show()
|
| 224 |
+
self.close()
|
| 225 |
+
|
| 226 |
+
except Exception as e:
|
| 227 |
+
show_error("launchMainWindow() in startup window", e)
|
| 228 |
+
|
| 229 |
+
def load_dropdown_data(self):
|
| 230 |
+
try:
|
| 231 |
+
GlobalSettings.mainWindow.getData()
|
| 232 |
+
GlobalSettings.mainWindow.fill_annotation_dropdown()
|
| 233 |
+
logger.debug("Successfully loaded organism/endo/annotation drop down information in Main.")
|
| 234 |
+
except Exception as e:
|
| 235 |
+
show_error("load_dropdown_data() in Main", e)
|
| 236 |
+
|
| 237 |
+
try:
|
| 238 |
+
GlobalSettings.MTWin.launch()
|
| 239 |
+
logger.debug("Successfully loaded organism/endo drop down information in Multi-targeting.")
|
| 240 |
+
except Exception as e:
|
| 241 |
+
show_error("load_dropdown_data() in Multi-targeting", e)
|
| 242 |
+
|
| 243 |
+
try:
|
| 244 |
+
GlobalSettings.pop_Analysis.launch()
|
| 245 |
+
logger.debug("Successfully loaded organism/endo drop down information in Population Analysis.")
|
| 246 |
+
except Exception as e:
|
| 247 |
+
show_error("load_dropdown_data() in Population Analysis", e)
|
| 248 |
+
|
| 249 |
+
def initialize_app_directories():
|
| 250 |
+
required_dirs = ["FNA", "GBFF"]
|
| 251 |
+
for directory in required_dirs:
|
| 252 |
+
path = os.path.join(GlobalSettings.CSPR_DB, directory)
|
| 253 |
+
if not os.path.exists(path):
|
| 254 |
+
os.makedirs(path, exist_ok=True)
|
| 255 |
+
logging.info(f"Directory created: {path}")
|
|
File without changes
|
|
@@ -0,0 +1,73 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import models.GlobalSettings as GlobalSettings
|
| 2 |
+
import os
|
| 3 |
+
from PyQt5 import QtWidgets, Qt, uic
|
| 4 |
+
import traceback
|
| 5 |
+
import math
|
| 6 |
+
from utils.ui import show_error, scale_ui
|
| 7 |
+
|
| 8 |
+
logger = GlobalSettings.logger
|
| 9 |
+
|
| 10 |
+
###########################################################
|
| 11 |
+
# closingWindow: this class is a little window where the user can select which files they want to delete
|
| 12 |
+
# Once they hit 'submit' it will delete all of the files selected, and close the program.
|
| 13 |
+
# If no files are selected, the program closes and no files are deleted
|
| 14 |
+
# Inputs are taking from the user (selecting files to delete and hitting submit), as well as GlobalSettings for the files in CSPR_DB
|
| 15 |
+
# Outputs are the files are deleting, and the program is closed
|
| 16 |
+
###########################################################
|
| 17 |
+
class closingWindow(QtWidgets.QMainWindow):
|
| 18 |
+
def __init__(self):
|
| 19 |
+
try:
|
| 20 |
+
super(closingWindow, self).__init__()
|
| 21 |
+
uic.loadUi(GlobalSettings.appdir + "ui/closing_window.ui", self)
|
| 22 |
+
self.setWindowTitle("Delete Files")
|
| 23 |
+
self.setWindowIcon(Qt.QIcon(GlobalSettings.appdir + "cas9image.ico"))
|
| 24 |
+
|
| 25 |
+
# Button
|
| 26 |
+
self.submit_button.clicked.connect(self.submit_and_close)
|
| 27 |
+
|
| 28 |
+
# Table
|
| 29 |
+
self.files_table.setColumnCount(1)
|
| 30 |
+
self.files_table.setShowGrid(True)
|
| 31 |
+
self.files_table.setHorizontalHeaderLabels("File Name;".split(";"))
|
| 32 |
+
self.files_table.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
|
| 33 |
+
self.files_table.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
|
| 34 |
+
self.files_table.setSelectionMode(QtWidgets.QAbstractItemView.MultiSelection)
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
scale_ui(self, custom_scale_width=400, custom_scale_height=300)
|
| 38 |
+
|
| 39 |
+
|
| 40 |
+
except Exception as e:
|
| 41 |
+
show_error("Error initializing closingWindow class.", e)
|
| 42 |
+
|
| 43 |
+
# this function will delete selected files, and then close the program
|
| 44 |
+
def submit_and_close(self):
|
| 45 |
+
try:
|
| 46 |
+
# loop through the whole table
|
| 47 |
+
for i in range(self.files_table.rowCount()):
|
| 48 |
+
tabWidget = self.files_table.item(i, 0)
|
| 49 |
+
|
| 50 |
+
# if that specific tab is selected, delete it. otherwise do nothing
|
| 51 |
+
if tabWidget.isSelected():
|
| 52 |
+
os.remove(tabWidget.text())
|
| 53 |
+
self.close()
|
| 54 |
+
except Exception as e:
|
| 55 |
+
show_error("Error in sumbit_and_close() in closing window.", e)
|
| 56 |
+
|
| 57 |
+
# this function gets all of the files from the CSPR_DB and puts them all into the table
|
| 58 |
+
def get_files(self):
|
| 59 |
+
try:
|
| 60 |
+
loopCount = 0
|
| 61 |
+
# get the file names from CSPR_DB
|
| 62 |
+
files_names = os.listdir(GlobalSettings.CSPR_DB)
|
| 63 |
+
files_names.sort(key=str.lower)
|
| 64 |
+
self.files_table.setRowCount(len(files_names))
|
| 65 |
+
|
| 66 |
+
# loop through and add them to the table
|
| 67 |
+
for file in files_names:
|
| 68 |
+
tabWidget = QtWidgets.QTableWidgetItem(file)
|
| 69 |
+
self.files_table.setItem(loopCount, 0, tabWidget)
|
| 70 |
+
loopCount += 1
|
| 71 |
+
self.files_table.resizeColumnsToContents()
|
| 72 |
+
except Exception as e:
|
| 73 |
+
show_error("Error in get_files() in closing window.", e)
|
|
@@ -1,27 +1,23 @@
|
|
| 1 |
-
import GlobalSettings
|
| 2 |
-
from Algorithms import get_table_headers
|
| 3 |
import os
|
| 4 |
from PyQt5 import QtWidgets, Qt, uic, QtCore, QtGui
|
| 5 |
import platform
|
| 6 |
import traceback
|
| 7 |
import math
|
|
|
|
| 8 |
|
| 9 |
-
#global logger
|
| 10 |
logger = GlobalSettings.logger
|
| 11 |
|
| 12 |
-
# Class: export_tool
|
| 13 |
# This class opens a window for the user to select where they want the CSV file exported to, and the name of the file
|
| 14 |
# It takes the highlighted data from the Results page, and creates a CSV file from that
|
| 15 |
class export_tool(QtWidgets.QMainWindow):
|
| 16 |
-
# init function. Sets all of the buttons
|
| 17 |
def __init__(self):
|
| 18 |
try:
|
| 19 |
-
# qt stuff
|
| 20 |
super(export_tool, self).__init__()
|
| 21 |
-
uic.loadUi(GlobalSettings.appdir + 'export_tool.ui', self)
|
| 22 |
self.setWindowIcon(Qt.QIcon(GlobalSettings.appdir + "cas9image.ico"))
|
| 23 |
|
| 24 |
-
# button connections
|
| 25 |
self.browse_button.clicked.connect(self.browseForFolder)
|
| 26 |
self.cancel_button.clicked.connect(self.cancel_function)
|
| 27 |
self.export_button.clicked.connect(self.export_function)
|
|
@@ -43,7 +39,6 @@ class export_tool(QtWidgets.QMainWindow):
|
|
| 43 |
font: bold 14pt 'Arial';} """
|
| 44 |
self.gRNA_Options.setStyleSheet(groupbox_style)
|
| 45 |
|
| 46 |
-
# variables
|
| 47 |
self.location = self.fileLocation_line_edit.text()
|
| 48 |
self.selected_table_items = []
|
| 49 |
self.window = ""
|
|
@@ -52,111 +47,10 @@ class export_tool(QtWidgets.QMainWindow):
|
|
| 52 |
self.gene_name = False
|
| 53 |
|
| 54 |
self.setWindowTitle("Export to CSV")
|
| 55 |
-
self
|
| 56 |
|
| 57 |
except Exception as e:
|
| 58 |
-
|
| 59 |
-
logger.critical(e)
|
| 60 |
-
logger.critical(traceback.format_exc())
|
| 61 |
-
msgBox = QtWidgets.QMessageBox()
|
| 62 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 63 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 64 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 65 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 66 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 67 |
-
msgBox.exec()
|
| 68 |
-
|
| 69 |
-
exit(-1)
|
| 70 |
-
|
| 71 |
-
#scale UI based on current screen
|
| 72 |
-
def scaleUI(self):
|
| 73 |
-
try:
|
| 74 |
-
self.repaint()
|
| 75 |
-
QtWidgets.QApplication.processEvents()
|
| 76 |
-
|
| 77 |
-
screen = QtWidgets.QApplication.desktop().screenNumber(QtWidgets.QApplication.desktop().cursor().pos())
|
| 78 |
-
screen = QtWidgets.QApplication.screens()[screen]
|
| 79 |
-
dpi = screen.physicalDotsPerInch()
|
| 80 |
-
width = screen.geometry().width()
|
| 81 |
-
height = screen.geometry().height()
|
| 82 |
-
|
| 83 |
-
# font scaling
|
| 84 |
-
fontSize = 12
|
| 85 |
-
self.fontSize = fontSize
|
| 86 |
-
self.centralWidget().setStyleSheet("font: " + str(fontSize) + "pt 'Arial';")
|
| 87 |
-
|
| 88 |
-
self.adjustSize()
|
| 89 |
-
|
| 90 |
-
currentWidth = self.size().width()
|
| 91 |
-
currentHeight = self.size().height()
|
| 92 |
-
|
| 93 |
-
# window scaling
|
| 94 |
-
# 1920x1080 => 1150x650
|
| 95 |
-
scaledWidth = int((width * 650) / 1920)
|
| 96 |
-
scaledHeight = int((height * 200) / 1080)
|
| 97 |
-
|
| 98 |
-
if scaledHeight < currentHeight:
|
| 99 |
-
scaledHeight = currentHeight
|
| 100 |
-
if scaledWidth < currentWidth:
|
| 101 |
-
scaledWidth = currentWidth
|
| 102 |
-
|
| 103 |
-
screen = QtWidgets.QApplication.desktop().screenNumber(QtWidgets.QApplication.desktop().cursor().pos())
|
| 104 |
-
centerPoint = QtWidgets.QApplication.desktop().screenGeometry(screen).center()
|
| 105 |
-
x = centerPoint.x()
|
| 106 |
-
y = centerPoint.y()
|
| 107 |
-
x = x - (math.ceil(scaledWidth / 2))
|
| 108 |
-
y = y - (math.ceil(scaledHeight / 2))
|
| 109 |
-
self.setGeometry(x, y, scaledWidth, scaledHeight)
|
| 110 |
-
|
| 111 |
-
self.repaint()
|
| 112 |
-
QtWidgets.QApplication.processEvents()
|
| 113 |
-
|
| 114 |
-
except Exception as e:
|
| 115 |
-
logger.critical("Error in scaleUI() in export_tool.")
|
| 116 |
-
logger.critical(e)
|
| 117 |
-
logger.critical(traceback.format_exc())
|
| 118 |
-
msgBox = QtWidgets.QMessageBox()
|
| 119 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 120 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 121 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 122 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 123 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 124 |
-
msgBox.exec()
|
| 125 |
-
|
| 126 |
-
exit(-1)
|
| 127 |
-
|
| 128 |
-
#center UI on current screen
|
| 129 |
-
def centerUI(self):
|
| 130 |
-
try:
|
| 131 |
-
self.repaint()
|
| 132 |
-
QtWidgets.QApplication.processEvents()
|
| 133 |
-
|
| 134 |
-
#center window on current screen
|
| 135 |
-
width = self.width()
|
| 136 |
-
height = self.height()
|
| 137 |
-
screen = QtWidgets.QApplication.desktop().screenNumber(QtWidgets.QApplication.desktop().cursor().pos())
|
| 138 |
-
centerPoint = QtWidgets.QApplication.desktop().screenGeometry(screen).center()
|
| 139 |
-
x = centerPoint.x()
|
| 140 |
-
y = centerPoint.y()
|
| 141 |
-
x = x - (math.ceil(width / 2))
|
| 142 |
-
y = y - (math.ceil(height / 2))
|
| 143 |
-
self.setGeometry(x, y, width, height)
|
| 144 |
-
|
| 145 |
-
self.repaint()
|
| 146 |
-
QtWidgets.QApplication.processEvents()
|
| 147 |
-
except Exception as e:
|
| 148 |
-
logger.critical("Error in centerUI() in export_tool.")
|
| 149 |
-
logger.critical(e)
|
| 150 |
-
logger.critical(traceback.format_exc())
|
| 151 |
-
msgBox = QtWidgets.QMessageBox()
|
| 152 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 153 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 154 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 155 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 156 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 157 |
-
msgBox.exec()
|
| 158 |
-
|
| 159 |
-
exit(-1)
|
| 160 |
|
| 161 |
# launch function. Called in Results.
|
| 162 |
# parameter expect: a list of the items selected from the window.
|
|
@@ -168,24 +62,12 @@ class export_tool(QtWidgets.QMainWindow):
|
|
| 168 |
self.fileLocation_line_edit.setText(GlobalSettings.CSPR_DB + "/")
|
| 169 |
self.selected_table_items = select_items
|
| 170 |
self.window = window
|
| 171 |
-
self
|
| 172 |
self.show()
|
| 173 |
self.activateWindow()
|
| 174 |
except Exception as e:
|
| 175 |
-
|
| 176 |
-
|
| 177 |
-
logger.critical(traceback.format_exc())
|
| 178 |
-
msgBox = QtWidgets.QMessageBox()
|
| 179 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 180 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 181 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 182 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 183 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 184 |
-
msgBox.exec()
|
| 185 |
-
|
| 186 |
-
exit(-1)
|
| 187 |
-
|
| 188 |
-
# export function
|
| 189 |
# Takes the path and file name and combines them
|
| 190 |
# Writes the header line, as well as ever line selected to that file
|
| 191 |
# calls the cancel function when it's done
|
|
@@ -321,48 +203,27 @@ class export_tool(QtWidgets.QMainWindow):
|
|
| 321 |
tmp_list.append(item.text())
|
| 322 |
it += 1
|
| 323 |
output_data.close()
|
| 324 |
-
# catch the permission exception
|
| 325 |
except PermissionError:
|
| 326 |
-
|
| 327 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 328 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 329 |
-
msgBox.setWindowTitle("File Cannot Open")
|
| 330 |
-
msgBox.setText("This file cannot be opened. Please make sure that the file is not opened elsewhere and try again.")
|
| 331 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Ok)
|
| 332 |
-
msgBox.exec()
|
| 333 |
return
|
| 334 |
|
| 335 |
-
# catch any other exception
|
| 336 |
except Exception as e:
|
| 337 |
-
|
| 338 |
return
|
| 339 |
|
| 340 |
""" Print "finished" message """
|
| 341 |
-
|
| 342 |
-
|
| 343 |
-
|
| 344 |
-
|
| 345 |
-
|
| 346 |
-
|
| 347 |
-
msgBox.exec()
|
| 348 |
|
| 349 |
# close the window
|
| 350 |
self.cancel_function()
|
| 351 |
-
|
| 352 |
except Exception as e:
|
| 353 |
-
|
| 354 |
-
|
| 355 |
-
logger.critical(traceback.format_exc())
|
| 356 |
-
msgBox = QtWidgets.QMessageBox()
|
| 357 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 358 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 359 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 360 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 361 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 362 |
-
msgBox.exec()
|
| 363 |
-
|
| 364 |
-
exit(-1)
|
| 365 |
-
|
| 366 |
# Resets everything to the init funciton
|
| 367 |
# then closes the window
|
| 368 |
def cancel_function(self):
|
|
@@ -375,19 +236,8 @@ class export_tool(QtWidgets.QMainWindow):
|
|
| 375 |
self.location = ""
|
| 376 |
self.hide()
|
| 377 |
except Exception as e:
|
| 378 |
-
|
| 379 |
-
|
| 380 |
-
logger.critical(traceback.format_exc())
|
| 381 |
-
msgBox = QtWidgets.QMessageBox()
|
| 382 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 383 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 384 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 385 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 386 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 387 |
-
msgBox.exec()
|
| 388 |
-
|
| 389 |
-
exit(-1)
|
| 390 |
-
|
| 391 |
# browse for folder function
|
| 392 |
# allows user to browse for a folder where to store the CSV file
|
| 393 |
def browseForFolder(self):
|
|
@@ -399,7 +249,6 @@ class export_tool(QtWidgets.QMainWindow):
|
|
| 399 |
if(os.path.isdir(mydir) == False):
|
| 400 |
return
|
| 401 |
|
| 402 |
-
|
| 403 |
if platform.system() == "Windows":
|
| 404 |
self.fileLocation_line_edit.setText(mydir + "\\")
|
| 405 |
self.location = mydir + "\\"
|
|
@@ -407,15 +256,4 @@ class export_tool(QtWidgets.QMainWindow):
|
|
| 407 |
self.fileLocation_line_edit.setText(mydir + "/")
|
| 408 |
self.location = mydir + "/"
|
| 409 |
except Exception as e:
|
| 410 |
-
|
| 411 |
-
logger.critical(e)
|
| 412 |
-
logger.critical(traceback.format_exc())
|
| 413 |
-
msgBox = QtWidgets.QMessageBox()
|
| 414 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 415 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 416 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 417 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 418 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 419 |
-
msgBox.exec()
|
| 420 |
-
|
| 421 |
-
exit(-1)
|
|
|
|
| 1 |
+
import models.GlobalSettings as GlobalSettings
|
| 2 |
+
from utils.Algorithms import get_table_headers
|
| 3 |
import os
|
| 4 |
from PyQt5 import QtWidgets, Qt, uic, QtCore, QtGui
|
| 5 |
import platform
|
| 6 |
import traceback
|
| 7 |
import math
|
| 8 |
+
from utils.ui import show_message, show_error, scale_ui, center_ui
|
| 9 |
|
|
|
|
| 10 |
logger = GlobalSettings.logger
|
| 11 |
|
|
|
|
| 12 |
# This class opens a window for the user to select where they want the CSV file exported to, and the name of the file
|
| 13 |
# It takes the highlighted data from the Results page, and creates a CSV file from that
|
| 14 |
class export_tool(QtWidgets.QMainWindow):
|
|
|
|
| 15 |
def __init__(self):
|
| 16 |
try:
|
|
|
|
| 17 |
super(export_tool, self).__init__()
|
| 18 |
+
uic.loadUi(GlobalSettings.appdir + 'ui/export_tool.ui', self)
|
| 19 |
self.setWindowIcon(Qt.QIcon(GlobalSettings.appdir + "cas9image.ico"))
|
| 20 |
|
|
|
|
| 21 |
self.browse_button.clicked.connect(self.browseForFolder)
|
| 22 |
self.cancel_button.clicked.connect(self.cancel_function)
|
| 23 |
self.export_button.clicked.connect(self.export_function)
|
|
|
|
| 39 |
font: bold 14pt 'Arial';} """
|
| 40 |
self.gRNA_Options.setStyleSheet(groupbox_style)
|
| 41 |
|
|
|
|
| 42 |
self.location = self.fileLocation_line_edit.text()
|
| 43 |
self.selected_table_items = []
|
| 44 |
self.window = ""
|
|
|
|
| 47 |
self.gene_name = False
|
| 48 |
|
| 49 |
self.setWindowTitle("Export to CSV")
|
| 50 |
+
scale_ui(self, custom_scale_width=650, custom_scale_height=200)
|
| 51 |
|
| 52 |
except Exception as e:
|
| 53 |
+
show_error("Error initializing export_tool class.", e)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 54 |
|
| 55 |
# launch function. Called in Results.
|
| 56 |
# parameter expect: a list of the items selected from the window.
|
|
|
|
| 62 |
self.fileLocation_line_edit.setText(GlobalSettings.CSPR_DB + "/")
|
| 63 |
self.selected_table_items = select_items
|
| 64 |
self.window = window
|
| 65 |
+
center_ui(self)
|
| 66 |
self.show()
|
| 67 |
self.activateWindow()
|
| 68 |
except Exception as e:
|
| 69 |
+
show_error("Error in launch() in export_tool.", e)
|
| 70 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 71 |
# Takes the path and file name and combines them
|
| 72 |
# Writes the header line, as well as ever line selected to that file
|
| 73 |
# calls the cancel function when it's done
|
|
|
|
| 203 |
tmp_list.append(item.text())
|
| 204 |
it += 1
|
| 205 |
output_data.close()
|
|
|
|
| 206 |
except PermissionError:
|
| 207 |
+
show_error("This file cannot be opened. Please make sure that the file is not opened elsewhere and try again.", e)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 208 |
return
|
| 209 |
|
|
|
|
| 210 |
except Exception as e:
|
| 211 |
+
show_error("Error in export_function() in export_tool.", e)
|
| 212 |
return
|
| 213 |
|
| 214 |
""" Print "finished" message """
|
| 215 |
+
show_message(
|
| 216 |
+
fontSize=12,
|
| 217 |
+
icon=QtWidgets.QMessageBox.Icon.Information,
|
| 218 |
+
title="Export Complete",
|
| 219 |
+
message=f"Export to {full_path} was successful."
|
| 220 |
+
)
|
|
|
|
| 221 |
|
| 222 |
# close the window
|
| 223 |
self.cancel_function()
|
|
|
|
| 224 |
except Exception as e:
|
| 225 |
+
show_error("Error in export_function() in export_tool.", e)
|
| 226 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 227 |
# Resets everything to the init funciton
|
| 228 |
# then closes the window
|
| 229 |
def cancel_function(self):
|
|
|
|
| 236 |
self.location = ""
|
| 237 |
self.hide()
|
| 238 |
except Exception as e:
|
| 239 |
+
show_error("Error in cancel_function() in export_tool.", e)
|
| 240 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 241 |
# browse for folder function
|
| 242 |
# allows user to browse for a folder where to store the CSV file
|
| 243 |
def browseForFolder(self):
|
|
|
|
| 249 |
if(os.path.isdir(mydir) == False):
|
| 250 |
return
|
| 251 |
|
|
|
|
| 252 |
if platform.system() == "Windows":
|
| 253 |
self.fileLocation_line_edit.setText(mydir + "\\")
|
| 254 |
self.location = mydir + "\\"
|
|
|
|
| 256 |
self.fileLocation_line_edit.setText(mydir + "/")
|
| 257 |
self.location = mydir + "/"
|
| 258 |
except Exception as e:
|
| 259 |
+
show_error("Error in browseForFolder() in export_tool.", e)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@@ -1,29 +1,26 @@
|
|
| 1 |
-
import GlobalSettings
|
| 2 |
import os
|
| 3 |
from PyQt5 import QtWidgets, Qt, uic, QtCore
|
| 4 |
from functools import partial
|
| 5 |
-
from CSPRparser import CSPRparser
|
| 6 |
import re
|
| 7 |
import platform
|
| 8 |
import traceback
|
| 9 |
import math
|
| 10 |
-
from
|
|
|
|
| 11 |
|
| 12 |
-
#global logger
|
| 13 |
logger = GlobalSettings.logger
|
| 14 |
|
| 15 |
-
# Class Name: genLibrary
|
| 16 |
# this class is a window that allows the user to select the settings for Generate Library
|
| 17 |
# When the user clicks Generate Library, it goes ahead and gets the Annotation Data needed
|
| 18 |
# Then the user can select the settings they want, and then hit submit.
|
| 19 |
# It creates a txt file with the data
|
| 20 |
class genLibrary(QtWidgets.QMainWindow):
|
| 21 |
-
|
| 22 |
def __init__(self):
|
| 23 |
try:
|
| 24 |
-
# qt stuff
|
| 25 |
super(genLibrary, self).__init__()
|
| 26 |
-
uic.loadUi(GlobalSettings.appdir + 'generate_library.ui', self)
|
| 27 |
self.setWindowTitle('Generate Library')
|
| 28 |
self.setWindowIcon(Qt.QIcon(GlobalSettings.appdir + 'cas9image.ico'))
|
| 29 |
|
|
@@ -40,14 +37,11 @@ class genLibrary(QtWidgets.QMainWindow):
|
|
| 40 |
self.Step3.setStyleSheet(groupbox_style.replace("Step1", "Step3"))
|
| 41 |
self.Step4.setStyleSheet(groupbox_style.replace("Step1", "Step4"))
|
| 42 |
|
| 43 |
-
|
| 44 |
-
# button connections
|
| 45 |
self.cancel_button.clicked.connect(self.cancel_function)
|
| 46 |
self.BrowseButton.clicked.connect(self.browse_function)
|
| 47 |
self.submit_button.clicked.connect(self.submit_data)
|
| 48 |
self.progressBar.setValue(0)
|
| 49 |
|
| 50 |
-
# variables
|
| 51 |
self.anno_data = dict()
|
| 52 |
self.kegg_nonKegg = ''
|
| 53 |
self.gen_lib_dict = dict()
|
|
@@ -65,118 +59,12 @@ class genLibrary(QtWidgets.QMainWindow):
|
|
| 65 |
# set the numbers for the minOn combo box
|
| 66 |
for i in range(19, 70):
|
| 67 |
self.minON_comboBox.addItem(str(i + 1))
|
| 68 |
-
|
| 69 |
-
|
| 70 |
-
self.scaleUI()
|
| 71 |
-
|
| 72 |
-
except Exception as e:
|
| 73 |
-
logger.critical("Error initializing generate library class.")
|
| 74 |
-
logger.critical(e)
|
| 75 |
-
logger.critical(traceback.format_exc())
|
| 76 |
-
msgBox = QtWidgets.QMessageBox()
|
| 77 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 78 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 79 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 80 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 81 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 82 |
-
msgBox.exec()
|
| 83 |
-
|
| 84 |
-
exit(-1)
|
| 85 |
-
|
| 86 |
-
#scale UI based on current screen
|
| 87 |
-
def scaleUI(self):
|
| 88 |
-
try:
|
| 89 |
-
self.repaint()
|
| 90 |
-
QtWidgets.QApplication.processEvents()
|
| 91 |
-
|
| 92 |
-
screen = QtWidgets.QApplication.desktop().screenNumber(QtWidgets.QApplication.desktop().cursor().pos())
|
| 93 |
-
screen = QtWidgets.QApplication.screens()[screen]
|
| 94 |
-
dpi = screen.physicalDotsPerInch()
|
| 95 |
-
width = screen.geometry().width()
|
| 96 |
-
height = screen.geometry().height()
|
| 97 |
-
|
| 98 |
-
# font scaling
|
| 99 |
-
fontSize = 12
|
| 100 |
-
self.fontSize = fontSize
|
| 101 |
-
self.centralWidget().setStyleSheet("font: " + str(fontSize) + "pt 'Arial';")
|
| 102 |
-
|
| 103 |
-
#scale title
|
| 104 |
-
fontSize = 30
|
| 105 |
-
self.label.setStyleSheet("font: bold " + str(fontSize) + "pt 'Arial';")
|
| 106 |
-
|
| 107 |
-
self.adjustSize()
|
| 108 |
-
|
| 109 |
-
currentWidth = self.size().width()
|
| 110 |
-
currentHeight = self.size().height()
|
| 111 |
-
|
| 112 |
-
# window scaling
|
| 113 |
-
# 1920x1080 => 800x650
|
| 114 |
-
scaledWidth = int((width * 950) / 1920)
|
| 115 |
-
scaledHeight = int((height * 500) / 1080)
|
| 116 |
-
|
| 117 |
-
if scaledHeight < currentHeight:
|
| 118 |
-
scaledHeight = currentHeight
|
| 119 |
-
if scaledWidth < currentWidth:
|
| 120 |
-
scaledWidth = currentWidth
|
| 121 |
-
|
| 122 |
-
screen = QtWidgets.QApplication.desktop().screenNumber(QtWidgets.QApplication.desktop().cursor().pos())
|
| 123 |
-
centerPoint = QtWidgets.QApplication.desktop().screenGeometry(screen).center()
|
| 124 |
-
x = centerPoint.x()
|
| 125 |
-
y = centerPoint.y()
|
| 126 |
-
x = x - (math.ceil(scaledWidth / 2))
|
| 127 |
-
y = y - (math.ceil(scaledHeight / 2))
|
| 128 |
-
self.setGeometry(x, y, scaledWidth, scaledHeight)
|
| 129 |
-
|
| 130 |
-
self.repaint()
|
| 131 |
-
QtWidgets.QApplication.processEvents()
|
| 132 |
|
| 133 |
except Exception as e:
|
| 134 |
-
|
| 135 |
-
|
| 136 |
-
logger.critical(traceback.format_exc())
|
| 137 |
-
msgBox = QtWidgets.QMessageBox()
|
| 138 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 139 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 140 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 141 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 142 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 143 |
-
msgBox.exec()
|
| 144 |
-
|
| 145 |
-
exit(-1)
|
| 146 |
-
|
| 147 |
-
#center UI on current screen
|
| 148 |
-
def centerUI(self):
|
| 149 |
-
try:
|
| 150 |
-
self.repaint()
|
| 151 |
-
QtWidgets.QApplication.processEvents()
|
| 152 |
-
|
| 153 |
-
#center window on current screen
|
| 154 |
-
width = self.width()
|
| 155 |
-
height = self.height()
|
| 156 |
-
screen = QtWidgets.QApplication.desktop().screenNumber(QtWidgets.QApplication.desktop().cursor().pos())
|
| 157 |
-
centerPoint = QtWidgets.QApplication.desktop().screenGeometry(screen).center()
|
| 158 |
-
x = centerPoint.x()
|
| 159 |
-
y = centerPoint.y()
|
| 160 |
-
x = x - (math.ceil(width / 2))
|
| 161 |
-
y = y - (math.ceil(height / 2))
|
| 162 |
-
self.setGeometry(x, y, width, height)
|
| 163 |
-
|
| 164 |
-
self.repaint()
|
| 165 |
-
QtWidgets.QApplication.processEvents()
|
| 166 |
-
except Exception as e:
|
| 167 |
-
logger.critical("Error in centerUI() in generate library.")
|
| 168 |
-
logger.critical(e)
|
| 169 |
-
logger.critical(traceback.format_exc())
|
| 170 |
-
msgBox = QtWidgets.QMessageBox()
|
| 171 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 172 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 173 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 174 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 175 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 176 |
-
msgBox.exec()
|
| 177 |
-
|
| 178 |
-
exit(-1)
|
| 179 |
-
|
| 180 |
# this function launches the window
|
| 181 |
# Parameters:
|
| 182 |
# annotation_data: a dictionary that has the data for the annotations searched for
|
|
@@ -192,7 +80,6 @@ class genLibrary(QtWidgets.QMainWindow):
|
|
| 192 |
self.process = QtCore.QProcess()
|
| 193 |
self.parser.fileName = org_file
|
| 194 |
|
| 195 |
-
|
| 196 |
# setting the path and file name fields
|
| 197 |
index1 = self.cspr_file.find('.')
|
| 198 |
if platform.system() == "Windows":
|
|
@@ -215,23 +102,11 @@ class genLibrary(QtWidgets.QMainWindow):
|
|
| 215 |
self.cspr_data = self.parser.gen_lib_parser(self.gen_lib_dict, GlobalSettings.mainWindow.endoChoice.currentText())
|
| 216 |
self.get_endo_data()
|
| 217 |
|
| 218 |
-
|
| 219 |
-
self.centerUI()
|
| 220 |
self.show()
|
| 221 |
self.activateWindow()
|
| 222 |
except Exception as e:
|
| 223 |
-
|
| 224 |
-
logger.critical(e)
|
| 225 |
-
logger.critical(traceback.format_exc())
|
| 226 |
-
msgBox = QtWidgets.QMessageBox()
|
| 227 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 228 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 229 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 230 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 231 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 232 |
-
msgBox.exec()
|
| 233 |
-
|
| 234 |
-
exit(-1)
|
| 235 |
|
| 236 |
def get_endo_data(self):
|
| 237 |
try:
|
|
@@ -258,19 +133,8 @@ class genLibrary(QtWidgets.QMainWindow):
|
|
| 258 |
break
|
| 259 |
f.close()
|
| 260 |
except Exception as e:
|
| 261 |
-
|
| 262 |
-
|
| 263 |
-
logger.critical(traceback.format_exc())
|
| 264 |
-
msgBox = QtWidgets.QMessageBox()
|
| 265 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 266 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 267 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 268 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 269 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 270 |
-
msgBox.exec()
|
| 271 |
-
|
| 272 |
-
exit(-1)
|
| 273 |
-
|
| 274 |
# this is here in case the user clicks 'x' instead of cancel. Just calls the cancel function
|
| 275 |
def closeEvent(self, event):
|
| 276 |
try:
|
|
@@ -282,19 +146,8 @@ class genLibrary(QtWidgets.QMainWindow):
|
|
| 282 |
else:
|
| 283 |
event.accept()
|
| 284 |
except Exception as e:
|
| 285 |
-
|
| 286 |
-
|
| 287 |
-
logger.critical(traceback.format_exc())
|
| 288 |
-
msgBox = QtWidgets.QMessageBox()
|
| 289 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 290 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 291 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 292 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 293 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 294 |
-
msgBox.exec()
|
| 295 |
-
|
| 296 |
-
exit(-1)
|
| 297 |
-
|
| 298 |
# this function takes all of the cspr data and compresses it again for off-target usage
|
| 299 |
def compress_file_off(self):
|
| 300 |
try:
|
|
@@ -314,19 +167,8 @@ class genLibrary(QtWidgets.QMainWindow):
|
|
| 314 |
f.write(output + '\n')
|
| 315 |
f.close()
|
| 316 |
except Exception as e:
|
| 317 |
-
|
| 318 |
-
|
| 319 |
-
logger.critical(traceback.format_exc())
|
| 320 |
-
msgBox = QtWidgets.QMessageBox()
|
| 321 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 322 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 323 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 324 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 325 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 326 |
-
msgBox.exec()
|
| 327 |
-
|
| 328 |
-
exit(-1)
|
| 329 |
-
|
| 330 |
# this function parses the temp_off file, which holds the off-target analysis results
|
| 331 |
# it also updates each target in the cspr_data dictionary to replace the endo with the target's results in off-target
|
| 332 |
def parse_off_file(self):
|
|
@@ -354,19 +196,8 @@ class genLibrary(QtWidgets.QMainWindow):
|
|
| 354 |
tempTuple = (self.cspr_data[gene][i][0], self.cspr_data[gene][i][1], self.cspr_data[gene][i][2], self.cspr_data[gene][i][3], self.cspr_data[gene][i][4], scoreDict[self.cspr_data[gene][i][1]])
|
| 355 |
self.cspr_data[gene][i] = tempTuple
|
| 356 |
except Exception as e:
|
| 357 |
-
|
| 358 |
-
|
| 359 |
-
logger.critical(traceback.format_exc())
|
| 360 |
-
msgBox = QtWidgets.QMessageBox()
|
| 361 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 362 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 363 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 364 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 365 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 366 |
-
msgBox.exec()
|
| 367 |
-
|
| 368 |
-
exit(-1)
|
| 369 |
-
|
| 370 |
# this function runs the off_target command
|
| 371 |
# NOTE: some changes may be needed to get it to work with other OS besides windows
|
| 372 |
def get_offTarget_data(self, num_targets, minScore, spaceValue, output_file, fiveseq):
|
|
@@ -385,15 +216,12 @@ class genLibrary(QtWidgets.QMainWindow):
|
|
| 385 |
#self.process.kill()
|
| 386 |
if did_work != -1:
|
| 387 |
self.cancel_function()
|
| 388 |
-
|
| 389 |
-
|
| 390 |
-
|
| 391 |
-
|
| 392 |
-
|
| 393 |
-
|
| 394 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Ok)
|
| 395 |
-
msgBox.exec()
|
| 396 |
-
|
| 397 |
os.remove(GlobalSettings.CSPR_DB + '/off_input.txt')
|
| 398 |
os.remove(GlobalSettings.CSPR_DB + '/temp_off.txt')
|
| 399 |
|
|
@@ -473,19 +301,8 @@ class genLibrary(QtWidgets.QMainWindow):
|
|
| 473 |
QtCore.QTimer.singleShot(100, partial(self.process.start, cmd))
|
| 474 |
self.process.finished.connect(finished)
|
| 475 |
except Exception as e:
|
| 476 |
-
|
| 477 |
-
|
| 478 |
-
logger.critical(traceback.format_exc())
|
| 479 |
-
msgBox = QtWidgets.QMessageBox()
|
| 480 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 481 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 482 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 483 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 484 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 485 |
-
msgBox.exec()
|
| 486 |
-
|
| 487 |
-
exit(-1)
|
| 488 |
-
|
| 489 |
# submit function
|
| 490 |
# this function takes all of the input from the window, and calls the generate function
|
| 491 |
# Still need to add the checks for 5' seq, and the percentage thing
|
|
@@ -512,103 +329,78 @@ class genLibrary(QtWidgets.QMainWindow):
|
|
| 512 |
elif self.space_line_edit.text().isdigit():
|
| 513 |
spaceValue = int(self.space_line_edit.text())
|
| 514 |
elif not self.space_line_edit.text().isdigit():
|
| 515 |
-
|
| 516 |
-
|
| 517 |
-
|
| 518 |
-
|
| 519 |
-
|
| 520 |
-
|
| 521 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Ok)
|
| 522 |
-
msgBox.exec()
|
| 523 |
-
|
| 524 |
return
|
| 525 |
# if space value is more than 200, default to 200
|
| 526 |
if spaceValue > 200:
|
| 527 |
spaceValue = 200
|
| 528 |
elif spaceValue < 0:
|
| 529 |
-
|
| 530 |
-
|
| 531 |
-
|
| 532 |
-
|
| 533 |
-
|
| 534 |
-
|
| 535 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Ok)
|
| 536 |
-
msgBox.exec()
|
| 537 |
-
|
| 538 |
return
|
| 539 |
|
| 540 |
if self.find_off_Checkbox.isChecked():
|
| 541 |
self.compress_file_off()
|
| 542 |
|
| 543 |
-
|
| 544 |
-
|
| 545 |
# get the fiveprimseq data and error check it
|
| 546 |
if self.fiveprimeseq.text() != '' and self.fiveprimeseq.text().isalpha():
|
| 547 |
fiveseq = self.fiveprimeseq.text()
|
| 548 |
elif self.fiveprimeseq.text() != '' and not self.fiveprimeseq.text().isalpha():
|
| 549 |
-
|
| 550 |
-
|
| 551 |
-
|
| 552 |
-
|
| 553 |
-
|
| 554 |
-
|
| 555 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Ok)
|
| 556 |
-
msgBox.exec()
|
| 557 |
-
|
| 558 |
return
|
| 559 |
|
| 560 |
-
|
| 561 |
# get the targeting range data, and error check it here
|
| 562 |
if not self.start_target_range.text().isdigit() or not self.end_target_range.text().isdigit():
|
| 563 |
-
|
| 564 |
-
|
| 565 |
-
|
| 566 |
-
|
| 567 |
-
|
| 568 |
-
|
| 569 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Ok)
|
| 570 |
-
msgBox.exec()
|
| 571 |
-
|
| 572 |
return
|
| 573 |
elif int(self.start_target_range.text()) >= int(self.end_target_range.text()):
|
| 574 |
-
|
| 575 |
-
|
| 576 |
-
|
| 577 |
-
|
| 578 |
-
|
| 579 |
-
|
| 580 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Ok)
|
| 581 |
-
msgBox.exec()
|
| 582 |
-
|
| 583 |
return
|
| 584 |
|
| 585 |
-
|
| 586 |
# if they check Off-Targeting
|
| 587 |
if self.find_off_Checkbox.isChecked():
|
| 588 |
# make sure its a digit
|
| 589 |
if self.maxOFF_comboBox.text() == '' or not self.maxOFF_comboBox.text().isdigit() and '.' not in self.maxOFF_comboBox.text():
|
| 590 |
-
|
| 591 |
-
|
| 592 |
-
|
| 593 |
-
|
| 594 |
-
|
| 595 |
-
|
| 596 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Ok)
|
| 597 |
-
msgBox.exec()
|
| 598 |
-
|
| 599 |
return
|
| 600 |
else:
|
| 601 |
# make sure it between 0 and .5
|
| 602 |
if not 0.0 < float(self.maxOFF_comboBox.text()) <= .5:
|
| 603 |
-
|
| 604 |
-
|
| 605 |
-
|
| 606 |
-
|
| 607 |
-
|
| 608 |
-
|
| 609 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Ok)
|
| 610 |
-
msgBox.exec()
|
| 611 |
-
|
| 612 |
return
|
| 613 |
# compress the data, and then run off-targeting
|
| 614 |
self.compress_file_off()
|
|
@@ -619,36 +411,21 @@ class genLibrary(QtWidgets.QMainWindow):
|
|
| 619 |
|
| 620 |
if did_work != -1:
|
| 621 |
self.cancel_function()
|
| 622 |
-
|
| 623 |
-
|
| 624 |
-
|
| 625 |
-
|
| 626 |
-
|
| 627 |
-
|
| 628 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Ok)
|
| 629 |
-
msgBox.exec()
|
| 630 |
-
|
| 631 |
except Exception as e:
|
| 632 |
-
|
| 633 |
-
|
| 634 |
-
logger.critical(traceback.format_exc())
|
| 635 |
-
msgBox = QtWidgets.QMessageBox()
|
| 636 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 637 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 638 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 639 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 640 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 641 |
-
msgBox.exec()
|
| 642 |
-
|
| 643 |
-
exit(-1)
|
| 644 |
-
|
| 645 |
-
# cancel function
|
| 646 |
# clears everything and hides the window
|
| 647 |
def cancel_function(self):
|
| 648 |
try:
|
| 649 |
if self.off_target_running:
|
| 650 |
msgBox = QtWidgets.QMessageBox()
|
| 651 |
-
msgBox.setStyleSheet("font: " + str(
|
| 652 |
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Question)
|
| 653 |
msgBox.setWindowTitle("Off-Targeting is running")
|
| 654 |
msgBox.setText(
|
|
@@ -685,20 +462,8 @@ class genLibrary(QtWidgets.QMainWindow):
|
|
| 685 |
|
| 686 |
self.hide()
|
| 687 |
except Exception as e:
|
| 688 |
-
|
| 689 |
-
|
| 690 |
-
logger.critical(traceback.format_exc())
|
| 691 |
-
msgBox = QtWidgets.QMessageBox()
|
| 692 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 693 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 694 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 695 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 696 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 697 |
-
msgBox.exec()
|
| 698 |
-
|
| 699 |
-
exit(-1)
|
| 700 |
-
|
| 701 |
-
# browse function
|
| 702 |
# allows the user to browse for a folder
|
| 703 |
# stores their selection in the output_path line edit
|
| 704 |
def browse_function(self):
|
|
@@ -718,18 +483,7 @@ class genLibrary(QtWidgets.QMainWindow):
|
|
| 718 |
else:
|
| 719 |
self.output_path.setText(mydir + "/")
|
| 720 |
except Exception as e:
|
| 721 |
-
|
| 722 |
-
logger.critical(e)
|
| 723 |
-
logger.critical(traceback.format_exc())
|
| 724 |
-
msgBox = QtWidgets.QMessageBox()
|
| 725 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 726 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 727 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 728 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 729 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 730 |
-
msgBox.exec()
|
| 731 |
-
|
| 732 |
-
exit(-1)
|
| 733 |
|
| 734 |
# this function builds the dictionary that is used in the generate function
|
| 735 |
# this is the version that builds it from data from feature_table, gbff, or gff
|
|
@@ -745,18 +499,7 @@ class genLibrary(QtWidgets.QMainWindow):
|
|
| 745 |
### Order: chromosome number, gene start, gene end, dir of gene, gene description, gene name/locus tag
|
| 746 |
self.gen_lib_dict[feature_name] = [chrom,int(feature.location.start),int(feature.location.end),get_strand(feature),get_description(feature),get_name(feature)]
|
| 747 |
except Exception as e:
|
| 748 |
-
|
| 749 |
-
logger.critical(e)
|
| 750 |
-
logger.critical(traceback.format_exc())
|
| 751 |
-
msgBox = QtWidgets.QMessageBox()
|
| 752 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 753 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 754 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 755 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 756 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 757 |
-
msgBox.exec()
|
| 758 |
-
|
| 759 |
-
exit(-1)
|
| 760 |
|
| 761 |
# generate function taken from Brian's code
|
| 762 |
def generate(self,num_targets_per_gene, score_limit, space, output_file, fiveseq):
|
|
@@ -773,15 +516,12 @@ class genLibrary(QtWidgets.QMainWindow):
|
|
| 773 |
endNum = endNum / 100
|
| 774 |
checkStartandEndBool = True
|
| 775 |
else:
|
| 776 |
-
|
| 777 |
-
|
| 778 |
-
|
| 779 |
-
|
| 780 |
-
|
| 781 |
-
|
| 782 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Ok)
|
| 783 |
-
msgBox.exec()
|
| 784 |
-
|
| 785 |
return -1
|
| 786 |
|
| 787 |
for gene in self.gen_lib_dict:
|
|
@@ -908,29 +648,15 @@ class genLibrary(QtWidgets.QMainWindow):
|
|
| 908 |
|
| 909 |
f.close()
|
| 910 |
except PermissionError:
|
| 911 |
-
|
| 912 |
-
|
| 913 |
-
|
| 914 |
-
|
| 915 |
-
|
| 916 |
-
|
| 917 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Ok)
|
| 918 |
-
msgBox.exec()
|
| 919 |
-
|
| 920 |
return -1
|
| 921 |
except Exception as e:
|
| 922 |
print(e)
|
| 923 |
return
|
| 924 |
except Exception as e:
|
| 925 |
-
|
| 926 |
-
logger.critical(e)
|
| 927 |
-
logger.critical(traceback.format_exc())
|
| 928 |
-
msgBox = QtWidgets.QMessageBox()
|
| 929 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 930 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 931 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 932 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 933 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 934 |
-
msgBox.exec()
|
| 935 |
-
|
| 936 |
-
exit(-1)
|
|
|
|
| 1 |
+
import models.GlobalSettings as GlobalSettings
|
| 2 |
import os
|
| 3 |
from PyQt5 import QtWidgets, Qt, uic, QtCore
|
| 4 |
from functools import partial
|
| 5 |
+
from models.CSPRparser import CSPRparser
|
| 6 |
import re
|
| 7 |
import platform
|
| 8 |
import traceback
|
| 9 |
import math
|
| 10 |
+
from utils.ui import show_message, show_error, scale_ui, center_ui
|
| 11 |
+
from views.annotation_functions import *
|
| 12 |
|
|
|
|
| 13 |
logger = GlobalSettings.logger
|
| 14 |
|
|
|
|
| 15 |
# this class is a window that allows the user to select the settings for Generate Library
|
| 16 |
# When the user clicks Generate Library, it goes ahead and gets the Annotation Data needed
|
| 17 |
# Then the user can select the settings they want, and then hit submit.
|
| 18 |
# It creates a txt file with the data
|
| 19 |
class genLibrary(QtWidgets.QMainWindow):
|
|
|
|
| 20 |
def __init__(self):
|
| 21 |
try:
|
|
|
|
| 22 |
super(genLibrary, self).__init__()
|
| 23 |
+
uic.loadUi(GlobalSettings.appdir + 'ui/generate_library.ui', self)
|
| 24 |
self.setWindowTitle('Generate Library')
|
| 25 |
self.setWindowIcon(Qt.QIcon(GlobalSettings.appdir + 'cas9image.ico'))
|
| 26 |
|
|
|
|
| 37 |
self.Step3.setStyleSheet(groupbox_style.replace("Step1", "Step3"))
|
| 38 |
self.Step4.setStyleSheet(groupbox_style.replace("Step1", "Step4"))
|
| 39 |
|
|
|
|
|
|
|
| 40 |
self.cancel_button.clicked.connect(self.cancel_function)
|
| 41 |
self.BrowseButton.clicked.connect(self.browse_function)
|
| 42 |
self.submit_button.clicked.connect(self.submit_data)
|
| 43 |
self.progressBar.setValue(0)
|
| 44 |
|
|
|
|
| 45 |
self.anno_data = dict()
|
| 46 |
self.kegg_nonKegg = ''
|
| 47 |
self.gen_lib_dict = dict()
|
|
|
|
| 59 |
# set the numbers for the minOn combo box
|
| 60 |
for i in range(19, 70):
|
| 61 |
self.minON_comboBox.addItem(str(i + 1))
|
| 62 |
+
|
| 63 |
+
scale_ui(self, custom_scale_width=950, custom_scale_height=500)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 64 |
|
| 65 |
except Exception as e:
|
| 66 |
+
show_error("Error initializing generate library class.", e)
|
| 67 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 68 |
# this function launches the window
|
| 69 |
# Parameters:
|
| 70 |
# annotation_data: a dictionary that has the data for the annotations searched for
|
|
|
|
| 80 |
self.process = QtCore.QProcess()
|
| 81 |
self.parser.fileName = org_file
|
| 82 |
|
|
|
|
| 83 |
# setting the path and file name fields
|
| 84 |
index1 = self.cspr_file.find('.')
|
| 85 |
if platform.system() == "Windows":
|
|
|
|
| 102 |
self.cspr_data = self.parser.gen_lib_parser(self.gen_lib_dict, GlobalSettings.mainWindow.endoChoice.currentText())
|
| 103 |
self.get_endo_data()
|
| 104 |
|
| 105 |
+
center_ui(self)
|
|
|
|
| 106 |
self.show()
|
| 107 |
self.activateWindow()
|
| 108 |
except Exception as e:
|
| 109 |
+
show_error("Error in launch() in generate library.", e)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 110 |
|
| 111 |
def get_endo_data(self):
|
| 112 |
try:
|
|
|
|
| 133 |
break
|
| 134 |
f.close()
|
| 135 |
except Exception as e:
|
| 136 |
+
show_error("Error in get_endo_data() in generate library.", e)
|
| 137 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 138 |
# this is here in case the user clicks 'x' instead of cancel. Just calls the cancel function
|
| 139 |
def closeEvent(self, event):
|
| 140 |
try:
|
|
|
|
| 146 |
else:
|
| 147 |
event.accept()
|
| 148 |
except Exception as e:
|
| 149 |
+
show_error("Error in closeEvent() in generate library.", e)
|
| 150 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 151 |
# this function takes all of the cspr data and compresses it again for off-target usage
|
| 152 |
def compress_file_off(self):
|
| 153 |
try:
|
|
|
|
| 167 |
f.write(output + '\n')
|
| 168 |
f.close()
|
| 169 |
except Exception as e:
|
| 170 |
+
show_error("Error in compress_file_off() in generate library.", e)
|
| 171 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 172 |
# this function parses the temp_off file, which holds the off-target analysis results
|
| 173 |
# it also updates each target in the cspr_data dictionary to replace the endo with the target's results in off-target
|
| 174 |
def parse_off_file(self):
|
|
|
|
| 196 |
tempTuple = (self.cspr_data[gene][i][0], self.cspr_data[gene][i][1], self.cspr_data[gene][i][2], self.cspr_data[gene][i][3], self.cspr_data[gene][i][4], scoreDict[self.cspr_data[gene][i][1]])
|
| 197 |
self.cspr_data[gene][i] = tempTuple
|
| 198 |
except Exception as e:
|
| 199 |
+
show_error("Error in parse_off_file() in generate library.", e)
|
| 200 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 201 |
# this function runs the off_target command
|
| 202 |
# NOTE: some changes may be needed to get it to work with other OS besides windows
|
| 203 |
def get_offTarget_data(self, num_targets, minScore, spaceValue, output_file, fiveseq):
|
|
|
|
| 216 |
#self.process.kill()
|
| 217 |
if did_work != -1:
|
| 218 |
self.cancel_function()
|
| 219 |
+
show_message(
|
| 220 |
+
fontSize=12,
|
| 221 |
+
icon=QtWidgets.QMessageBox.Icon.Information,
|
| 222 |
+
title="Library Generated!",
|
| 223 |
+
message="CASPER has finished generating your library!"
|
| 224 |
+
)
|
|
|
|
|
|
|
|
|
|
| 225 |
os.remove(GlobalSettings.CSPR_DB + '/off_input.txt')
|
| 226 |
os.remove(GlobalSettings.CSPR_DB + '/temp_off.txt')
|
| 227 |
|
|
|
|
| 301 |
QtCore.QTimer.singleShot(100, partial(self.process.start, cmd))
|
| 302 |
self.process.finished.connect(finished)
|
| 303 |
except Exception as e:
|
| 304 |
+
show_error("Error in get_offTarget_data() in generate library.", e)
|
| 305 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 306 |
# submit function
|
| 307 |
# this function takes all of the input from the window, and calls the generate function
|
| 308 |
# Still need to add the checks for 5' seq, and the percentage thing
|
|
|
|
| 329 |
elif self.space_line_edit.text().isdigit():
|
| 330 |
spaceValue = int(self.space_line_edit.text())
|
| 331 |
elif not self.space_line_edit.text().isdigit():
|
| 332 |
+
show_message(
|
| 333 |
+
fontSize=12,
|
| 334 |
+
icon=QtWidgets.QMessageBox.Icon.Critical,
|
| 335 |
+
title="Error",
|
| 336 |
+
message="Please enter integers only for space between guides."
|
| 337 |
+
)
|
|
|
|
|
|
|
|
|
|
| 338 |
return
|
| 339 |
# if space value is more than 200, default to 200
|
| 340 |
if spaceValue > 200:
|
| 341 |
spaceValue = 200
|
| 342 |
elif spaceValue < 0:
|
| 343 |
+
show_message(
|
| 344 |
+
fontSize=12,
|
| 345 |
+
icon=QtWidgets.QMessageBox.Icon.Critical,
|
| 346 |
+
title="Error",
|
| 347 |
+
message="Please enter a space-value that is 0 or greater."
|
| 348 |
+
)
|
|
|
|
|
|
|
|
|
|
| 349 |
return
|
| 350 |
|
| 351 |
if self.find_off_Checkbox.isChecked():
|
| 352 |
self.compress_file_off()
|
| 353 |
|
|
|
|
|
|
|
| 354 |
# get the fiveprimseq data and error check it
|
| 355 |
if self.fiveprimeseq.text() != '' and self.fiveprimeseq.text().isalpha():
|
| 356 |
fiveseq = self.fiveprimeseq.text()
|
| 357 |
elif self.fiveprimeseq.text() != '' and not self.fiveprimeseq.text().isalpha():
|
| 358 |
+
show_message(
|
| 359 |
+
fontSize=12,
|
| 360 |
+
icon=QtWidgets.QMessageBox.Icon.Critical,
|
| 361 |
+
title="Error",
|
| 362 |
+
message="Please make sure only the letters A, T, G, or C are added into 5' End specificity box."
|
| 363 |
+
)
|
|
|
|
|
|
|
|
|
|
| 364 |
return
|
| 365 |
|
|
|
|
| 366 |
# get the targeting range data, and error check it here
|
| 367 |
if not self.start_target_range.text().isdigit() or not self.end_target_range.text().isdigit():
|
| 368 |
+
show_message(
|
| 369 |
+
fontSize=12,
|
| 370 |
+
icon=QtWidgets.QMessageBox.Icon.Critical,
|
| 371 |
+
title="Error",
|
| 372 |
+
message="Error: Please make sure that the start and end target ranges are numbers only. Please make sure that start is 0 or greater, and end is 100 or less. "
|
| 373 |
+
)
|
|
|
|
|
|
|
|
|
|
| 374 |
return
|
| 375 |
elif int(self.start_target_range.text()) >= int(self.end_target_range.text()):
|
| 376 |
+
show_message(
|
| 377 |
+
fontSize=12,
|
| 378 |
+
icon=QtWidgets.QMessageBox.Icon.Critical,
|
| 379 |
+
title="Error",
|
| 380 |
+
message="Please make sure that the start number is always less than the end number"
|
| 381 |
+
)
|
|
|
|
|
|
|
|
|
|
| 382 |
return
|
| 383 |
|
|
|
|
| 384 |
# if they check Off-Targeting
|
| 385 |
if self.find_off_Checkbox.isChecked():
|
| 386 |
# make sure its a digit
|
| 387 |
if self.maxOFF_comboBox.text() == '' or not self.maxOFF_comboBox.text().isdigit() and '.' not in self.maxOFF_comboBox.text():
|
| 388 |
+
show_message(
|
| 389 |
+
fontSize=12,
|
| 390 |
+
icon=QtWidgets.QMessageBox.Icon.Critical,
|
| 391 |
+
title="Error",
|
| 392 |
+
message="Please enter only numbers for Maximum Off-Target Score. It cannot be left blank"
|
| 393 |
+
)
|
|
|
|
|
|
|
|
|
|
| 394 |
return
|
| 395 |
else:
|
| 396 |
# make sure it between 0 and .5
|
| 397 |
if not 0.0 < float(self.maxOFF_comboBox.text()) <= .5:
|
| 398 |
+
show_message(
|
| 399 |
+
fontSize=12,
|
| 400 |
+
icon=QtWidgets.QMessageBox.Icon.Critical,
|
| 401 |
+
title="Error",
|
| 402 |
+
message="Please enter a max off-target score between 0 and 0.5!"
|
| 403 |
+
)
|
|
|
|
|
|
|
|
|
|
| 404 |
return
|
| 405 |
# compress the data, and then run off-targeting
|
| 406 |
self.compress_file_off()
|
|
|
|
| 411 |
|
| 412 |
if did_work != -1:
|
| 413 |
self.cancel_function()
|
| 414 |
+
show_message(
|
| 415 |
+
fontSize=12,
|
| 416 |
+
icon=QtWidgets.QMessageBox.Icon.Critical,
|
| 417 |
+
title="Library Generated!",
|
| 418 |
+
message="CASPER has finished generating your library!"
|
| 419 |
+
)
|
|
|
|
|
|
|
|
|
|
| 420 |
except Exception as e:
|
| 421 |
+
show_error("Error in submit_data() in generate library.", e)
|
| 422 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 423 |
# clears everything and hides the window
|
| 424 |
def cancel_function(self):
|
| 425 |
try:
|
| 426 |
if self.off_target_running:
|
| 427 |
msgBox = QtWidgets.QMessageBox()
|
| 428 |
+
msgBox.setStyleSheet("font: " + str(12) + "pt 'Arial'")
|
| 429 |
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Question)
|
| 430 |
msgBox.setWindowTitle("Off-Targeting is running")
|
| 431 |
msgBox.setText(
|
|
|
|
| 462 |
|
| 463 |
self.hide()
|
| 464 |
except Exception as e:
|
| 465 |
+
show_error("Error in cancel_function() in generate library.", e)
|
| 466 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 467 |
# allows the user to browse for a folder
|
| 468 |
# stores their selection in the output_path line edit
|
| 469 |
def browse_function(self):
|
|
|
|
| 483 |
else:
|
| 484 |
self.output_path.setText(mydir + "/")
|
| 485 |
except Exception as e:
|
| 486 |
+
show_error("Error in browse_function() in generate library.", e)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 487 |
|
| 488 |
# this function builds the dictionary that is used in the generate function
|
| 489 |
# this is the version that builds it from data from feature_table, gbff, or gff
|
|
|
|
| 499 |
### Order: chromosome number, gene start, gene end, dir of gene, gene description, gene name/locus tag
|
| 500 |
self.gen_lib_dict[feature_name] = [chrom,int(feature.location.start),int(feature.location.end),get_strand(feature),get_description(feature),get_name(feature)]
|
| 501 |
except Exception as e:
|
| 502 |
+
show_error("Error in build_dict_non_kegg() in generate library.", e)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 503 |
|
| 504 |
# generate function taken from Brian's code
|
| 505 |
def generate(self,num_targets_per_gene, score_limit, space, output_file, fiveseq):
|
|
|
|
| 516 |
endNum = endNum / 100
|
| 517 |
checkStartandEndBool = True
|
| 518 |
else:
|
| 519 |
+
show_message(
|
| 520 |
+
fontSize=12,
|
| 521 |
+
icon=QtWidgets.QMessageBox.Icon.Critical,
|
| 522 |
+
title="Invalid Targeting Range:",
|
| 523 |
+
message="Please select a targeting range between 0 and 100."
|
| 524 |
+
)
|
|
|
|
|
|
|
|
|
|
| 525 |
return -1
|
| 526 |
|
| 527 |
for gene in self.gen_lib_dict:
|
|
|
|
| 648 |
|
| 649 |
f.close()
|
| 650 |
except PermissionError:
|
| 651 |
+
show_message(
|
| 652 |
+
fontSize=12,
|
| 653 |
+
icon=QtWidgets.QMessageBox.Icon.Critical,
|
| 654 |
+
title="File Cannot Open",
|
| 655 |
+
message="This file cannot be opened. Please make sure that the file is not opened elsewhere and try again."
|
| 656 |
+
)
|
|
|
|
|
|
|
|
|
|
| 657 |
return -1
|
| 658 |
except Exception as e:
|
| 659 |
print(e)
|
| 660 |
return
|
| 661 |
except Exception as e:
|
| 662 |
+
show_error("Error in generate() in generate library.", e)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@@ -1,5 +1,5 @@
|
|
| 1 |
import sys, os
|
| 2 |
-
import GlobalSettings
|
| 3 |
from PyQt5 import QtWidgets, uic, QtGui, QtCore, Qt
|
| 4 |
import PyQt5.QtWebEngineWidgets
|
| 5 |
from PyQt5.QtWidgets import QApplication
|
|
@@ -12,8 +12,8 @@ import glob
|
|
| 12 |
import ssl
|
| 13 |
import traceback
|
| 14 |
import webbrowser
|
|
|
|
| 15 |
|
| 16 |
-
#global logger
|
| 17 |
logger = GlobalSettings.logger
|
| 18 |
|
| 19 |
ssl._create_default_https_context = ssl._create_unverified_context
|
|
@@ -22,7 +22,6 @@ class WebEnginePage(PyQt5.QtWebEngineWidgets.QWebEnginePage):
|
|
| 22 |
def certificateError(self, certificateError):
|
| 23 |
print("ssl error")
|
| 24 |
|
| 25 |
-
|
| 26 |
class genomebrowser(QtWidgets.QWidget):
|
| 27 |
def __init__(self, parent=None):
|
| 28 |
try:
|
|
@@ -30,18 +29,8 @@ class genomebrowser(QtWidgets.QWidget):
|
|
| 30 |
default_config.setProtocol(QtNetwork.QSsl.TlsV1_2)
|
| 31 |
QtNetwork.QSslConfiguration.setDefaultConfiguration(default_config)
|
| 32 |
except Exception as e:
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
logger.critical(traceback.format_exc())
|
| 36 |
-
msgBox = QtWidgets.QMessageBox()
|
| 37 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 38 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 39 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 40 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 41 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 42 |
-
msgBox.exec()
|
| 43 |
-
exit(-1)
|
| 44 |
-
|
| 45 |
def splitStringNCBI(self, longString):
|
| 46 |
try:
|
| 47 |
return (longString).split(':')[2]
|
|
@@ -66,19 +55,8 @@ class genomebrowser(QtWidgets.QWidget):
|
|
| 66 |
return genomeList
|
| 67 |
|
| 68 |
except Exception as e:
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
logger.critical(traceback.format_exc())
|
| 72 |
-
msgBox = QtWidgets.QMessageBox()
|
| 73 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 74 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 75 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 76 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 77 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 78 |
-
msgBox.exec()
|
| 79 |
-
|
| 80 |
-
exit(-1)
|
| 81 |
-
|
| 82 |
def createHtml(self, genomeList):
|
| 83 |
try:
|
| 84 |
htmlString1 = """
|
|
@@ -135,18 +113,8 @@ class genomebrowser(QtWidgets.QWidget):
|
|
| 135 |
|
| 136 |
raw.write(htmlString3)
|
| 137 |
except Exception as e:
|
| 138 |
-
|
| 139 |
-
|
| 140 |
-
logger.critical(traceback.format_exc())
|
| 141 |
-
msgBox = QtWidgets.QMessageBox()
|
| 142 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 143 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 144 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 145 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 146 |
-
msgBox.exec()
|
| 147 |
-
|
| 148 |
-
exit(-1)
|
| 149 |
-
|
| 150 |
def createGraph(self, p):
|
| 151 |
try:
|
| 152 |
selectedGenome = p.annotation_files.currentText()
|
|
@@ -183,16 +151,4 @@ class genomebrowser(QtWidgets.QWidget):
|
|
| 183 |
### Add logic for Linux ?
|
| 184 |
webbrowser.open(file_path, new=2)
|
| 185 |
except Exception as e:
|
| 186 |
-
|
| 187 |
-
|
| 188 |
-
logger.critical(e)
|
| 189 |
-
logger.critical(traceback.format_exc())
|
| 190 |
-
msgBox = QtWidgets.QMessageBox()
|
| 191 |
-
msgBox.setStyleSheet("font: " + str(self.fontSize) + "pt 'Arial'")
|
| 192 |
-
msgBox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
|
| 193 |
-
msgBox.setWindowTitle("Fatal Error")
|
| 194 |
-
msgBox.setText("Fatal Error:\n"+str(e)+ "\n\nFor more information on this error, look at CASPER.log in the application folder.")
|
| 195 |
-
msgBox.addButton(QtWidgets.QMessageBox.StandardButton.Close)
|
| 196 |
-
msgBox.exec()
|
| 197 |
-
|
| 198 |
-
exit(-1)
|
|
|
|
| 1 |
import sys, os
|
| 2 |
+
import models.GlobalSettings as GlobalSettings
|
| 3 |
from PyQt5 import QtWidgets, uic, QtGui, QtCore, Qt
|
| 4 |
import PyQt5.QtWebEngineWidgets
|
| 5 |
from PyQt5.QtWidgets import QApplication
|
|
|
|
| 12 |
import ssl
|
| 13 |
import traceback
|
| 14 |
import webbrowser
|
| 15 |
+
from utils.ui import show_error
|
| 16 |
|
|
|
|
| 17 |
logger = GlobalSettings.logger
|
| 18 |
|
| 19 |
ssl._create_default_https_context = ssl._create_unverified_context
|
|
|
|
| 22 |
def certificateError(self, certificateError):
|
| 23 |
print("ssl error")
|
| 24 |
|
|
|
|
| 25 |
class genomebrowser(QtWidgets.QWidget):
|
| 26 |
def __init__(self, parent=None):
|
| 27 |
try:
|
|
|
|
| 29 |
default_config.setProtocol(QtNetwork.QSsl.TlsV1_2)
|
| 30 |
QtNetwork.QSslConfiguration.setDefaultConfiguration(default_config)
|
| 31 |
except Exception as e:
|
| 32 |
+
show_error("Error initializing genomebrowser class.", e)
|
| 33 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 34 |
def splitStringNCBI(self, longString):
|
| 35 |
try:
|
| 36 |
return (longString).split(':')[2]
|
|
|
|
| 55 |
return genomeList
|
| 56 |
|
| 57 |
except Exception as e:
|
| 58 |
+
show_error("Error in ncbiAPI() in genomebrowser.", e)
|
| 59 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 60 |
def createHtml(self, genomeList):
|
| 61 |
try:
|
| 62 |
htmlString1 = """
|
|
|
|
| 113 |
|
| 114 |
raw.write(htmlString3)
|
| 115 |
except Exception as e:
|
| 116 |
+
show_error("Error in createHtml() in genomebrowser.", e)
|
| 117 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 118 |
def createGraph(self, p):
|
| 119 |
try:
|
| 120 |
selectedGenome = p.annotation_files.currentText()
|
|
|
|
| 151 |
### Add logic for Linux ?
|
| 152 |
webbrowser.open(file_path, new=2)
|
| 153 |
except Exception as e:
|
| 154 |
+
show_error("Error in createGraph() in genomebrowser.", e)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|